web-dev-qa-db-fra.com

Comment se désinscrire d'un abonnement socket.io?

Supposons que des objets souscrivent à un serveur de socket comme ceci:

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

Ces objets ont une courte durée de vie et sont fréquemment créés, générant de nombreux abonnements. Cela semble être une fuite de mémoire et une situation sujette aux erreurs qui seraient intuitivement évitées de cette façon:

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

avant que l'objet ne soit supprimé, mais hélas, il n'y a pas de méthode off dans le socket. Existe-t-il une autre méthode pour cela?

Edit: n'ayant trouvé aucune réponse, j'affecte une méthode vide pour écraser la méthode wrapper pour le gestionnaire d'événement d'origine, un exemple suit.

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;
56
Bijou Trouvaille

En regardant la source de socket.io.js (que je n'ai pu trouver nulle part dans la documentation), j'ai trouvé ces deux fonctions:

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

J'ai utilisé removeAllListeners avec succès dans mon application; vous devriez pouvoir choisir parmi ceux-ci:

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

De plus, je ne pense pas que votre solution de cbProxy = _blank fonctionnerait réellement; cela n'affecterait que la variable cbProxy, pas tout événement socket.io réel.

74
Andrew Magee

Si vous souhaitez créer des écouteurs qui "écoutent" une seule fois, utilisez socket.once('news',func). Socket.io détournera automatiquement l'auditeur après que l'événement se soit produit - il est appelé "écouteur volatile".

30
András Endre

En regardant le code de la version actuelle du client Socket.io (1.4.8), il semble que désactivé , removeAllListeners , removeEventListener pointent tous vers la même fonction.

Appeler l'un de ceux-ci, en fournissant le nom de l'événement et/ou le rappel, donne le résultat souhaité. Ne rien fournir du tout semble tout réinitialiser.

Veuillez faire attention à l'argument fn/callback . Il doit s'agir de la même instance utilisée dans le code.

Exemple:

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

Fonctionnerait comme prévu.

Exemple (fonctionnera également):

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

Veuillez faire attention à ce que le rappel que vous essayez de supprimer soit celui que vous avez transmis (celui-ci peut apporter beaucoup de confusion et de frustration). Cet exemple implémente un wrapper autour du rappel initial, en essayant de supprimer ce qui ne fonctionnerait pas car le rappel réel ajouté est une instance de fermeture non divulguée: http://www.html5rocks.com/en/tutorials/frameworks/angular- websockets /

Voici le lien vers cette ligne spécifique dans la base de code: https://github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597

22
Pjotr

Socket.io version 0.9.16 implémente removeListener mais pas off.

Vous pouvez utiliser removeListener au lieu de off lors de la désinscription, ou simplement implémenter off comme suit:

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

Si vous utilisez l'approche d'abonnement aux événements Backbone listenTo, vous devrez implémenter ce qui précède lorsque Backbone appelle off lors de la désinscription des événements.

5
deedw

J'ai trouvé que dans socket.io 0.9.11 et Chrome24 socket.io removeListener ne fonctionne pas.

cette version modifiée fonctionne pour moi:

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;
    };
3
radiofrequency

Suppression d'un écouteur d'événements sur le client

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

Étant donné que j'avais un peu de mal à faire en sorte que ce travail soit compris, je sonnerais ici aussi, avec une réponse mise à jour pour 2017. Merci à @Pjotr ​​d'avoir souligné qu'il doit s'agir de la même instance de rappel.

Exemple avec Angular2 TypeScript dans un service socket-io.subscriber. Notez le 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);
  }
1
Joshua Ohana

Pré-stockez les événements à l'aide d'un tableau et au moment où vous devez vous désinscrire, utilisez la méthode off, qui est une méthode intégrée de 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")
0
Raz

Pour ajouter à @Andrew Magee, voici un exemple de désabonnement aux événements socket.io dans Angular JS, et fonctionne bien sûr avec Vanilla JS:

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

Écoutez les événements:

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);
});
0
loonison101

Également sur Java client, cela peut être fait de la même manière avec le client Javascript. J'ai collé depuis 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);
0
efkan