如何取消订阅 socket.io 订阅?
假设有对象向套接字服务器进行订阅,如下所示:
socket.on('news', obj.socketEvent)
这些对象的生命周期很短,并且频繁创建,会生成许多订阅。这看起来像是内存泄漏和容易出错的情况,直观上可以通过这种方式来防止:
socket.off('news', obj.socketEvent)
在删除对象之前使用 ,但是可惜的是,没有' t 套接字中的 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;
Suppose there are objects making subscriptions to a socket server like so:
socket.on('news', obj.socketEvent)
These objects have a short life span and are frequently created, generating many subscriptions. This seems like a memory leak and an error prone situation which would intuitively be prevented this way:
socket.off('news', obj.socketEvent)
before the object is deleted, but alas, there isn't an off
method in the socket. Is there another method meant for this?
Edit: having found no answer I'm assigning a blank method to overwrite the wrapper method for the original event handler, an example follows.
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;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(11)
查看当前版本的 Socket.io 客户端(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.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;
};
由于我在做这项工作时遇到了一些麻烦,所以我也想在这里插话,并提供 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);
}
同样在 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);
要添加到@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);
});
这对我在 Angular 8 和 React 16.8 中都有帮助:
receiveMessage() {
let newCallback = (data) => {
this.eventEmitter.emit('add-message-response', data);
};
this.socket.on('add-message-response', newCallback);
this.subscriptions.push({key: 'add-message-response', callback: newCallback});
}
receiveMessageRemoveSocketListener() {
this.findAndRemoveSocketEventListener('add-message-response');
}
findAndRemoveSocketEventListener (eventKey) {
let foundListener = this.subscriptions.find( (subscription) => subscription.key === eventKey );
if(!foundListener) {
return;
}
this.socket.removeListener(foundListener.key, foundListener.callback);
this.subscriptions = this.subscriptions.filter( (subscription) => subscription.key !== eventKey );
}
使用订阅数组的原因是,当您多次订阅一个事件并且不从订阅列表中删除未订阅的订阅时,您一开始很可能是对的当您从列表中删除订阅时,但后面的订阅将不会被删除,因为每次取消订阅事件时您只会找到第一个实例。
您可以简单地调用 receiveMessage();订阅事件并 receiveMessageRemoveSocketListener();取消订阅。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
通过查看socket.io.js的源代码(在任何地方的文档中都找不到它),我发现了这两个函数:
我在我的应用程序中成功使用了
removeAllListeners
;您应该能够从以下选项中进行选择:另外,我认为您的
cbProxy = _blank
解决方案实际上不起作用;这只会影响 cbProxy 变量,而不影响任何实际的 socket.io 事件。From looking at the source of socket.io.js (couldn't find it in documentation anywhere), I found these two functions:
I used
removeAllListeners
successfully in my app; you should be able to choose from these:Also, I don't think your solution of
cbProxy = _blank
would actually work; that would only affect thecbProxy
variable, not any actual socket.io event.