如何避免在新连接上的套接字中多次调用setInterval内的api?

问题描述 投票:0回答:1

我正在尝试实现套接字,其中用户请求带有 id 的函数,并且在拥有 id 后,我每秒都会点击一个 api 并向用户发出响应

问题:每当新用户请求相同的 id 时,它都会再次调用具有相同 id 的相同 api

目标:我试图实现如果 setInterval 已经使用相同的 id 运行,那么它不应该再次调用,而只是开始发出响应。

我的代码:

socket.on('fancy' , async (data) => {
    checkInterval = setInterval(async _ => {
      callapi(data.match_id).then( fancy => {
        socket.emit(`fancy_${data.match_id}`, fancy)
      })
    }, 1000)
  })

callapi = (id) => {
  var options = {
    'method': 'POST',
    'url': 'url',
    formData: {
      'id': id
    }
  };
  return new Promise((resolve, reject) => {
    request(options, function (error, response) {
      let resp = {}
      if (error) reject(error)
      resolve({status: 'success', data: JSON.parse(response.body).data})
    });
  })
}

任何建议都会有很大帮助!

javascript socket.io
1个回答
0
投票

我处理这个问题的方法是创建一个

Class
来处理多种幻想 -

为了完整起见,这是我昨天在评论中发送的内容 - 它解决了问题中的要求。

class Fancy {
    static fancies = {};
    static add(match_id, socket) {
        if (!Fancy.fancies[match_id]) {
            Fancy.fancies[match_id] = new Fancy(match_id);
        }
        Fancy.fancies[match_id].subscribe(socket);
    }
 
    subscribers = [];
 
    constructor(match_id) {
        this.match_id = match_id;
        this.checkInterval = setInterval(async () => {
            const fancy = await callapi(this.match_id);
            this.subscribers.forEach((socket) =>
                socket.emit(`fancy_${this.match_id}`, fancy)
            );
        });
    }
    subscribe(socket) {
        if (!this.subscribers.find((sock) => sock === socket)) {
            this.subscribers.push(socket);
        }
    }
}
 
socket.on('fancy' , ({match_id}) => Fancy.add(match_id, socket));

注意:虽然这是一个

class
- 仅需要使用静态
add
方法。

当然,这不能处理断开连接,也不能处理用户从“幻想”中“取消订阅”的能力 - 根据评论

因此,要扩展该代码,它并没有太大不同 - 只需添加几个静态方法和一些实例方法

remove
静态方法 - 现有
add
的逆方法,以及从所有实例中删除套接字的
disconnect
静态方法。

对于实例方法,添加

unsubscribe
start
stop
方法

class Fancy {
    static fancies = {};
    static add(match_id, socket) {
        if (!Fancy.fancies[match_id]) {
            Fancy.fancies[match_id] = new Fancy(match_id);
        }
        Fancy.fancies[match_id].subscribe(socket);
    }
    
    static remove(match_id, socket) {
        Fancy.fancies[match_id]?.unsubscribe(socket);
    }
    
    static disconnect(socket) {
        Fancy.fancies.forEach(fancy => fancy.unsubscribe(socket));
    }
    
    // instance properties/methods
    
    subscribers = [];

    constructor(match_id) {
        this.match_id = match_id;
    }
    
    start() {
        if (!this.checkInterval) {
            this.checkInterval = setInterval(async () => {
                const fancy = await callapi(this.match_id);
                this.subscribers.forEach((socket) =>
                    socket.emit(`fancy_${this.match_id}`, fancy)
                );
            });
        }
    }
    
    stop() {
        clearInterval(this.setInterval);
        this.checkInterval = null;
    }
    
    unsubscribe(socket) {
        this.subscribers = this.subscribers.filter(sock => sock !== socket);
        if (this.subscribers.length === 0) {
            this.stop();
        }
    }
    
    subscribe(socket) {
        if (!this.subscribers.find((sock) => sock === socket)) {
            this.subscribers.push(socket);
            if (this.subscribers.length === 1) {
                this.start();
            }
        }
    }
}

socket.on('fancy' , ({match_id}) => Fancy.add(match_id, socket));
socket.on('unfancy' , ({match_id}) => Fancy.remove(match_id, socket));
socket.on('close', () => Fancy.disconnect(socket));

stop
/
start
方法的替代方法是保持间隔运行,但仅在有任何“订阅者”时才发出 API 请求

这稍微简化了代码,只需添加一个实例方法(取消订阅)

类似这样的:

class Fancy {
    static fancies = {};
    static add(match_id, socket) {
        if (!Fancy.fancies[match_id]) {
            Fancy.fancies[match_id] = new Fancy(match_id);
        }
        Fancy.fancies[match_id].subscribe(socket);
    }
    
    static remove(match_id, socket) {
        Fancy.fancies[match_id]?.unsubscribe(socket);
    }
    
    static disconnect(socket) {
        Fancy.fancies.forEach(fancy => fancy.unsubscribe(socket));
    }
    
    // instance properties/methods
    
    subscribers = [];

    constructor(match_id) {
        this.match_id = match_id;
        this.checkInterval = setInterval(async () => {
            if (this.subscribers.length) {
                const fancy = await callapi(this.match_id);
                this.subscribers.forEach((socket) =>
                    socket.emit(`fancy_${this.match_id}`, fancy)
                );
            }
        });
    }
    
    unsubscribe(socket) {
        this.subscribers = this.subscribers.filter(sock => sock !== socket);
    }
    
    subscribe(socket) {
        if (!this.subscribers.find((sock) => sock === socket)) {
            this.subscribers.push(socket);
        }
    }
}

就我个人而言,我会使用最后一个解决方案,当没有订阅者时,设置一个实际上不执行任何操作的时间间隔不会对性能造成影响

© www.soinside.com 2019 - 2024. All rights reserved.