简体   繁体   English

如何取消订阅socket.io订阅?

[英]How to unsubscribe from a socket.io subscription?

Suppose there are objects making subscriptions to a socket server like so: 假设存在对套接字服务器进行订阅的对象,如下所示:

socket.on('news', obj.socketEvent)

These objects have a short life span and are frequently created, generating many subscriptions. 这些对象的生命周期很短,并且经常被创建,从而生成许多订阅。 This seems like a memory leak and an error prone situation which would intuitively be prevented this way: 这似乎是一个内存泄漏和容易出错的情况,直观地阻止这种情况:

socket.off('news', obj.socketEvent)

before the object is deleted, but alas, there isn't an off method in the socket. 在删除对象之前,但是,套接字中没有off方法。 Is there another method meant for this? 还有另一种方法吗?

Edit : having found no answer I'm assigning a blank method to overwrite the wrapper method for the original event handler, an example follows. 编辑 :找不到答案我正在指定一个空白方法来覆盖原始事件处理程序的包装器方法,下面是一个示例。

var _blank = function(){};

var cbProxy = function(){
    obj.socketEvent.apply(obj, arguments)
};
var cbProxyProxy = function(){
    cbProxy.apply ({}, arguments)
}
socket.on('news', cbProxyProxy);

// ...and to unsubscribe 
cbProxy = _blank;

From looking at the source of socket.io.js (couldn't find it in documentation anywhere), I found these two functions: 从查看socket.io.js的源代码(无法在任何地方的文档中找到它),我发现了这两个函数:

removeListener = function(name, fn)
removeAllListeners = function(name)

I used removeAllListeners successfully in my app; 我在我的应用程序中成功使用了removeAllListeners ; you should be able to choose from these: 你应该可以从这些中选择:

socket.removeListener("news", cbProxy);
socket.removeAllListeners("news");

Also, I don't think your solution of cbProxy = _blank would actually work; 另外,我不认为你的cbProxy = _blank解决方案实际上会起作用; that would only affect the cbProxy variable, not any actual socket.io event. 这只会影响cbProxy变量,而不会影响任何实际的socket.io事件。

If you want to create listeners that "listens" only once use socket.once('news',func) . 如果你想创建只能“监听”一次的监听器,请使用socket.once('news',func) Socket.io automatically will distroy the listener after the event happened - it's called "volatile listener". 事件发生后,Socket.io会自动破坏侦听器 - 它被称为“volatile listener”。

Looking at the code of current version of Socket.io Client (1.4.8) it seems that off , removeAllListeners , removeEventListener are all pointing to the same function. 看看当前版本的Socket.io Client(1.4.8)的代码,似乎offremoveAllListenersremoveEventListener都指向同一个函数。

Calling any of those, providing event name and/or callback, gives the desired result. 调用其中任何一个,提供事件名称和/或回调,都会产生所需的结果。 Not providing anything at all seems to reset everything. 根本没有提供任何东西似乎重置了一切。

Please do be cautious about the fn/callback argument. 请注意fn / callback参数。 It has to be the same instance used in the code. 它必须与代码中使用的实例相同。

Example: 例:

var eventCallback = function(data) {
  // do something nice
};
socket.off('eventName', eventCallback);

Would work as expected. 会按预期工作。

Example (will also work): 示例(也将起作用):

function eventCallback(data) {
  // do something nice
}
socket.off('eventName', eventCallback);

Please be cautious that the callback you are trying to remove is the one that you passed in (this one can bring a lot of confusion and frustration). 请小心,您要删除的回调是您传入的回调(这可能带来很多混乱和挫折)。 This example implements a wrapper around initial callback, trying to remove that would not work as the real callback being added is an undisclosed closure instance: http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/ 这个例子实现了一个围绕初始回调的包装器,试图删除那个不起作用,因为添加的真正回调是一个未公开的闭包实例: http//www.html5rocks.com/en/tutorials/frameworks/angular-websockets/

Here is the link to that specific line in the codebase: https://github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597 以下是代码库中该特定行的链接: https//github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597

Socket.io version 0.9.16 implements removeListener but not off . Socket.io版本0.9.16实现了removeListener但没有off

You can use removeListener instead of off when unsubscribing, or simply implement off as follows: 您可以使用removeListener而不是off退订时,或者干脆实施off ,如下所示:

  var socket = io.connect(url);
  socket.off = socket.removeListener;

If you are using the Backbone listenTo event subscription approach, you'll need to implement the above as Backbone calls off when unsubscribing events. 如果您使用的是骨干listenTo事件订阅方法,您需要实现上述为骨架的要求off退订事件时。

I found that in socket.io 0.9.11 and Chrome24 socket.io removeListener doesn't work. 我发现在socket.io 0.9.11和Chrome24 socket.io removeListener不起作用。

this modified version works for me: 这个修改版本适合我:

EventEmitter.prototype.removeListener = function (name, fn) {
        if (this.$events && this.$events[name]) {
            var list = this.$events[name];

            if (io.util.isArray(list)) {
                var pos = -1;

                for (var i = 0, l = list.length; i < l; i++) {
                    if (list[i].toString() === fn.toString() || (list[i].listener && list[i].listener === fn)) {
                        pos = i;
                        break;
                    }
                }

                if (pos < 0) {
                    return this;
                }

                list.splice(pos, 1);

                if (!list.length) {
                    delete this.$events[name];
                }
            } else  {
                    if (list.toString() === fn.toString() || (list.listener && list.listener === fn)) {

                       delete this.$events[name];
                    }
            }
        }

        return this;
    };

Removing an event listener on the client 删除客户端上的事件侦听器

var Socket = io.connect();
Socket.removeListener('test', test);

Since I had a spot of troubles making this work figured I'd chime in here as well, along with a nice updated answer for 2017. Thanks to @Pjotr for pointing out that it has to be the same callback instance. 由于我有一些麻烦使得这项工作得到了解决,我也会在这里发布,以及2017年的一个很好的更新答案。感谢@Pjotr​​指出它必须是相同的回调实例。

Example with Angular2 TypeScript in a socket-io.subscriber service. 在socket-io.subscriber服务中使用Angular2 TypeScript的示例。 Note the "newCallback" wrapper 注意“newCallback”包装器

  private subscriptions: Array<{
    key: string,
    callback: Function
  }>;

  constructor() {
    this.subscriptions = [];
  }

  subscribe(key: string, callback: Function) {
    let newCallback = (response) => callback(response);
    this.socket.on(key, newCallback);
    return this.subscriptions.push({key: key, callback: newCallback}) - 1;
  }

  unsubscribe(i: number) {
    this.socket.removeListener(this.subscriptions[i].key, this.subscriptions[i].callback);
  }

To add to @Andrew Magee, here is an example of unsubscribing socket.io events in Angular JS, and of course works with Vanilla JS: 要添加到@Andrew Magee,这是一个在Angular JS中取消订阅socket.io事件的示例,当然也适用于Vanilla JS:

function handleCarStarted ( data ) { // Do stuff }
function handleCarStopped ( data ) { // Do stuff }

Listen for events: 听取事件:

var io = $window.io(); // Probably put this in a factory, not controller instantiation
io.on('car.started', handleCarStarted);
io.on('car.stopped', handleCarStopped);


$scope.$on('$destroy', function () {
    io.removeListener('car.started', handleCarStarted);
    io.removeListener('car.stopped', handleCarStopped);
});

Also on java client, it can be done the same way with the Javascript client. 同样在java客户端上,它可以用Javascript客户端以相同的方式完成。 I've pasted from socket.io . 我已经从socket.io粘贴了。

// remove all listeners of the connect event
socket.off(Socket.EVENT_CONNECT);

listener = new Emitter.Listener() { ... };
socket.on(Socket.EVENT_CONNECT, listener);
// remove the specified listener
socket.off(Socket.EVENT_CONNECT, listener);

Pre-store the events using an array, and by the time you need to unsubscribe them, use the off method, which is a built in method from socket.io: 使用数组预先存储事件,并在需要取消订阅时使用off方法,这是socket.io中的内置方法:

// init
var events = []

// store
events.push("eventName")
// subscribe
socket.on("eventName", cb)

// remove
events = events.filter(event => event!="eventName")
// unsubscribe
socket.off("eventName")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM