Как отказаться от подписки на 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;
Ответы
Ответ 1
От взгляда на источник socket.io.js(не удалось найти его в документации в любом месте), я нашел эти две функции:
removeListener = function(name, fn)
removeAllListeners = function(name)
Я успешно использовал removeAllListeners
в своем приложении; вы должны быть в состоянии выбрать из них:
socket.removeListener("news", cbProxy);
socket.removeAllListeners("news");
Кроме того, я не думаю, что ваше решение cbProxy = _blank
действительно работает; это повлияет только на переменную cbProxy
, а не на фактическое событие socket.io.
Ответ 2
Если вы хотите создать слушателей, которые "прослушивают" только один раз, используйте socket.once('news',func)
. Socket.io автоматически отключит слушателя после случившегося события - он называется "volatile listenener".
Ответ 3
Глядя на код текущей версии Socket.io Client (1.4.8), кажется, что off, removeAllListeners, removeEventListener все указывающие на одну и ту же функцию.
Вызов любого из них, предоставление имени события и/или обратного вызова, дает желаемый результат. Не предоставление чего-либо вообще похоже на reset все.
Пожалуйста, будьте осторожны с аргументом 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
Ответ 4
Socket.io версия 0.9.16 реализует removeListener
, но не off
.
Вы можете использовать removeListener
вместо off
при отмене подписки или просто реализовать off
следующим образом:
var socket = io.connect(url);
socket.off = socket.removeListener;
Если вы используете подход подписки на подписку
Ответ 5
Я обнаружил, что в 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;
};
Ответ 6
Удаление прослушивателя событий на клиенте
var Socket = io.connect();
Socket.removeListener('test', test);
Ответ 7
Чтобы добавить к @Andrew Magee, вот пример отказа от подписки на события socket.io в Angular JS и, конечно же, работает с Vanilla 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);
});
Ответ 8
Также на клиенте 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);
Ответ 9
Так как у меня было место неприятностей, и эта работа показала, что я тоже звоню вместе с хорошим обновленным ответом на 2017. Благодаря @Pjotr за то, что он должен быть одним и тем же экземпляром обратного вызова.
/p >
Пример с Angular2 TypeScript в службе socket-io.subscriber. Обратите внимание на оболочку 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);
}