2012-02-23 4 views
48

Предположим, что есть объекты, что делает подписку на сервер сокета, как так:Как отписаться от подписки на socket.io?

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

Эти объекты имеют короткий срок службы и часто создаются, производя много подписок. Это похоже на утечку памяти и склонной ситуации ошибок, которые интуитивно можно предотвратить таким образом:

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

, прежде чем объект будет удален, но, увы, не является off метод в гнезде. Есть ли другой способ для этого?

Редактировать: не нашел ответа. Я назначаю пустой метод для перезаписывания метода-оболочки для исходного обработчика события. Ниже приведен пример.

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; 

ответ

69

Глядя на источник socket.io.js (не мог найти его в документации в любом месте), я нашел эти две функции:

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

Я успешно использовал removeAllListeners в мое приложение; Вы должны быть в состоянии выбрать из них:

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

Кроме того, я не думаю, что ваше решение cbProxy = _blank будет реально работать; что повлияет только на переменную cbProxy, а не на фактическое событие socket.io.

+0

Это похоже на работу, событие исчезает из SocketNamespace, хотя мне еще предстоит провести обширное тестирование этой части. Также вы были правы в отношении прокси-решения, поэтому он обновлен для его юмора –

+0

Это не работает? WTF cbProxy есть? –

+1

Что не работает? 'cbProxy' был методом обратного вызова, определенным OP. –

3

Я нашел, что в socket.io 0.9.11 и Chrome24 socket.io removeListener не работает.

это модифицированная версия работает для меня:

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

Если вы хотите создать слушателей, что «слушает» только один раз использовать socket.once('news',func). Socket.io автоматически отключит слушателя после события - он называется «volatile listenener».

5

Socket.io версия 0.9.16 реализует removeListener, но не off.

Вы можете использовать removeListener вместо off когда отписки, или просто реализовать off следующим образом:

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

Если вы используете Backbone listenTo событий подписки подход, вам необходимо реализовать выше как Backbone вызовов off при отписании событий.

1

Удаление прослушивателя события на клиенте

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

Чтобы добавить в Маг @ Андрей, вот пример отписки сокета.И.О. события в угловых JS, и, конечно, работает с ванильным JS:

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

Послушаю для событий:

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

Также на java клиента, это может быть сделано так же, как с клиентом JavaScript. Я вставил с 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

Глядя на код текущей версии Клиента Socket.io (1.4.8), кажется, что от, removeAllListeners, removeEventListener все указывает на ту же функцию.

Вызов любого из них, предоставляющий имя события и/или обратный вызов, дает желаемый результат. Не предлагая ничего, похоже, все сбрасывает.

Пожалуйста, будьте осторожны относительно аргумента fn/callback. Он должен быть тем же самым экземпляром, который используется в коде.

Пример:

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

будет работать, как ожидалось.

Пример (также будет работать):

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

Пожалуйста, будьте осторожны, что обратный вызов вы пытаетесь удалить тот, который вы прошли в (это один может принести много путаницы и разочарования). Этот пример реализует обертку вокруг исходной функции обратного вызова, пытаясь удалить, что не будет работать, как реальный обратный вызов добавляется в нераскрытой закрытия экземпляра: http://www.html5rocks.com/en/tutorials/frameworks/angular-websockets/

Вот ссылка на эту конкретную строку в коде: https://github.com/socketio/socket.io-client/blob/master/socket.io.js#L1597

+1

Этот ответ требует большего количества оборотов, так как большинство других являются неполными и/или крайне устаревшими. –

1

Так как у меня было место неприятностей, и эта работа показала, что я тоже перезвоню здесь, а также хороший обновленный ответ на 2017. Благодаря @Pjotr ​​за то, что он должен быть одним и тем же экземпляром обратного вызова.

Пример с Angular2 TypeScript в сервисе socket-io.subscriber. Обратите внимание на обертку «newCallback»

 Смежные вопросы

  • Нет связанных вопросов^_^