假设存在对套接字服务器进行订阅的对象,如下所示:
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;
从查看socket.io.js的源代码(无法在任何地方的文档中找到它),我发现了这两个函数:
removeListener = function(name, fn)
removeAllListeners = function(name)
我在我的应用程序中成功使用了removeAllListeners
;你应该可以从这些中选择:
socket.removeListener("news", cbProxy);
socket.removeAllListeners("news");
另外,我认为你的cbProxy = _blank
解决方案实际上不会起作用;这只会影响cbProxy
变量,而不会影响任何实际的socket.io事件。
使用数组预先存储事件,并在需要取消订阅时使用off方法,这是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")
如果你想创建只听“一次”使用socket.once('news',func)
的监听器。事件发生后,Socket.io会自动破坏侦听器 - 它被称为“volatile listener”。
看看当前版本的Socket.io Client(1.4.8)的代码,似乎off,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
Socket.io版本0.9.16实现removeListener
但不实现off
。
取消订阅时,您可以使用removeListener
而不是off
,或者只需按如下方式实现off
:
var socket = io.connect(url);
socket.off = socket.removeListener;
如果您正在使用Backbone listenTo
事件订阅方法,则在取消订阅事件时,您需要实现上述操作,因为Backbone会调用off
。
我发现在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;
};
删除客户端上的事件侦听器
var Socket = io.connect();
Socket.removeListener('test', test);
由于我有一些麻烦使得这项工作得到了解决,我也会在这里发布,以及2017年的一个很好的更新答案。感谢@Pjotr指出它必须是相同的回调实例。
在socket-io.subscriber服务中使用Angular2 TypeScript的示例。注意“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);
}
要添加到@Andrew Magee,这是一个在Angular JS中取消订阅socket.io事件的示例,当然也适用于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);
});
同样在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);