Miguel
Miguel

Reputation: 1211

Remove multiple socket.io listeners recursively

I'm coding an application with node.js and socket.io where users can talk with each others in personal chat rooms. Everyone can have multiple opened chat rooms. When the user wants to exit a chat room, system has to remove every socket listener of the room.

websocket.on('createRoom', function(roomID) {
    ...
    var room = generateRoom();
    ...

    // Leaving room
    $('#exitButton').on('click', function() {
        // Removes
        websocket.removeAllListeners('createRoom');
    });

    // User joins the room
    websocket.on('main/roomJoin/'+roomID, function(username) {
        alert(username + ' has joined the room');
    });

    ...

    websocket.on('chat/messageReceived/'+roomID, function(message) {
        room.printMessage(message);
    });
});

The problem is that removeAllListeners doesn't remove the inner listeners, so if another user enters the room after the other exits, he receives the alert.

Another way to do this is to place the listeners outside, but it's harder to manage the multiple rooms.

Thanks.

Upvotes: 3

Views: 3115

Answers (1)

Ankit Aggarwal
Ankit Aggarwal

Reputation: 1546

I know you've already solved the problem but I'll answer anyway so people know what's going on.

1) removeAllListeners() only removes the array of callbacks for the event in question; it does not affect any other events at all.

When you define an eventListener (i.e. on('xyz', function(){}) you append the callback function to an array indexed by the name of the event supplied. This array is a member of the object in question, in your case the "webSocket" object. webSocket.on("createRoom", function(){}) adds the function to an object similar to

webSocket.listeners = {
    "createRoom: [ function ],
    "someOtherEvent": [ function, function, function ]
}

webSocket.removeAllListeners('createRoom') will simply remove the createRoom key and its associated value from the object without affecting any other events:

webSocket.listeners = { "someOtherEvent": [ function, function, function ] }

2) Though the roomJoin and messageReceived events were defined within the createRoom event's callback function, they are still operating on the same instance of the webSocket object. So you end up with a listeners object similar to:

webSocket.listeners = {
    "createRoom: [ function ],
    "main/roomJoin: [ function ],
    "chat/messageReceived": [ function ]
}

Combined with the information from point #1 above, webSocket.removeAllListeners('createRoom') will yield the following:

webSocket.listeners = {
    "main/roomJoin: [ function ],
    "chat/messageReceived": [ function ]
}

Just because these two events are defined within a callback for another event does not mean they are in anyway associated to that "parent" event. As you've figured out by now, the only way to remove these listeners is to remove them explicitly:

$('#exitButton').on('click', function() {
    // Removes
    websocket.removeAllListeners('createRoom');
    websocket.removeAllListeners('main/roomJoin');
    websocket.removeAllListeners('chat/messageReceived');
});

Upvotes: 6

Related Questions