How to unsubscribe from a socket.io subscription?

58,875

Solution 1

From looking at the source of socket.io.js (couldn't find it in documentation anywhere), I found these two functions:

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

I used removeAllListeners successfully in my app; 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; that would only affect the cbProxy variable, not any actual socket.io event.

Solution 2

If you want to create listeners that "listens" only once use socket.once('news',func). Socket.io automatically will distroy the listener after the event happened - it's called "volatile listener".

Solution 3

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.

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. 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/

Here is the link to that specific line in the codebase: https://github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597

Solution 4

Socket.io version 0.9.16 implements removeListener but not off.

You can use removeListener instead of off when unsubscribing, or simply implement off as follows:

  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.

Solution 5

I found that in socket.io 0.9.11 and Chrome24 socket.io removeListener doesn't work.

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;
    };
Share:
58,875
Bijou Trouvaille
Author by

Bijou Trouvaille

Bijou is a mathematics enthusiast, a philosophy ponderer and a professional programmer.

Updated on September 12, 2020

Comments

  • Bijou Trouvaille
    Bijou Trouvaille over 3 years

    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. 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;
    
  • Bijou Trouvaille
    Bijou Trouvaille about 12 years
    That seems to work, the event disappears from SocketNamespace though I'm yet to do extensive testing on this part. Also you were right about the proxy solution, so it's updated for the humour of it
  • Andrew Magee
    Andrew Magee over 8 years
    What isn't working? cbProxy was a callback method defined by the OP.
  • Anson Kao
    Anson Kao over 7 years
    This answer needs more upvotes, as most of the other ones are incomplete and/or extremely out of date.
  • Martin Schneider
    Martin Schneider about 6 years
    If you are using socket.io-client npm package then this is working best, since removeAllListeners() is parameterless (so you can't specify eventName).
  • Koushik Shom Choudhury
    Koushik Shom Choudhury almost 4 years
    Neither callback of off fires, not does the off works if a callback is given.
  • ViniciusArruda
    ViniciusArruda about 3 years
    Link to the docs here.