2012-02-23 17 views
48

Supponiamo che ci siano oggetti che fanno abbonamenti a un server socket in questo modo:Come annullare l'iscrizione a un abbonamento socket.io?

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

Questi oggetti hanno una vita breve e sono spesso creati, generando molti abbonamenti. Ciò sembra come una perdita di memoria e una situazione incline errore che sarebbe intuitivamente essere impedita in questo modo:

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

prima che l'oggetto viene eliminato, ma purtroppo, non esiste un metodo off nella presa. C'è un altro metodo pensato per questo?

Modifica: non ho trovato risposta Sto assegnando un metodo vuoto per sovrascrivere il metodo wrapper per il gestore di eventi originale, ne segue un esempio.

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; 

risposta

69

Dalla guardando il sorgente di socket.io.js (non poteva trovare nella documentazione da nessuna parte), ho trovato queste due funzioni:

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

ho usato removeAllListeners successo nella mia app; si dovrebbe essere in grado di scegliere tra questi:

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

Inoltre, non credo che la soluzione di cbProxy = _blank sarebbe effettivamente lavorare; ciò influenzerebbe solo la variabile cbProxy, non un vero evento socket.io.

+0

Sembra funzionare, l'evento scompare da SocketNamespace anche se devo ancora effettuare test approfonditi su questa parte. Inoltre avevi ragione sulla soluzione proxy, quindi è aggiornato per il suo umore –

+0

Questo non funziona? CbProxy WTF è? –

+1

Che cosa non funziona? 'cbProxy' era un metodo di callback definito dall'OP. –

3

Ho trovato che in socket.io 0.9.11 e Chrome24 socket.io removeListener non funziona.

questa versione modificata funziona per 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; 
    }; 
26

Se si desidera creare ascoltatori che "ascolta" solo una volta usare socket.once('news',func). Socket.io distrae automaticamente l'ascoltatore dopo che è accaduto l'evento - si chiama "ascoltatore volatile".

5

Socket.io versione 0.9.16 strumenti removeListener ma non off.

È possibile utilizzare removeListener invece di off quando cancellarsi, o semplicemente implementare off come segue:

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

Se si utilizza la spina dorsale di sottoscrizione approccio listenTo evento, sarà necessario attuare quanto sopra come chiamate Backbone off in caso di annullamento dell'iscrizione di eventi.

1

Rimozione di un listener di eventi sul client

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

Per aggiungere al @Andrew Magee, qui è un esempio di cancellarsi presa.eventi io in angolare JS, e, naturalmente, funziona con Vanilla JS:

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

intercettare gli eventi:

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

Anche su java cliente, si può fare allo stesso modo con il client JavaScript. Ho incollato da 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); 
12

Guardando il codice della versione corrente di Socket.io client (1.4.8) sembra che off, removeAllListeners, removeEventListener indicano tutti la stessa funzione.

La chiamata di uno di quelli, fornendo nome evento e/o richiamata, fornisce il risultato desiderato. Non fornire nulla sembra resettare tutto.

Si prega di fare attenzione all'argomento fn/callback. Deve essere la stessa istanza utilizzata nel codice.

Esempio:

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

avrebbe funzionato come previsto.

Esempio (funziona anche):

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

Si prega di essere prudenti che la richiamata si sta tentando di eliminare è quello che avete passato in (questo può portare un sacco di confusione e frustrazione). Questo esempio implementa un wrapper per richiamata iniziale, cercando di rimuovere che non avrebbe funzionato come il vero callback viene aggiunto è un'istanza di chiusura riservate: http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/

Ecco il link a quella linea specifica nel codice di base: https://github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597

+1

Questa risposta richiede più upvotes, poiché la maggior parte degli altri è incompleta e/o estremamente obsoleta. –

1

Dato che ho avuto un problema con questo lavoro ho capito che mi sarei trovato anche qui, insieme a una bella risposta aggiornata per il 2017. Grazie a @Pjotr ​​per aver sottolineato che deve essere la stessa istanza di callback.

Esempio con Angular2 TypeScript in un servizio socket-io.subscriber. Notare il 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); 
    } 
Problemi correlati