将一个函数绑定到多个套接字
Binding a function to multiple sockets
io.on('connection', function(socket) {
socket.join('myRoom');
if(condition){
bindFunctions();
}
});
假设第 4 个套接字连接时 condition
为真。下面的代码成功地将 .on
处理程序绑定到 myRoom
.
中的所有套接字
bindFunctions(){
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
var socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
//This is always the same property, no matter who calls this function.
});
}
}
然而,当 'my event'
触发时,无论哪个客户端触发它,socket
对象始终是连接的第 4 个套接字。它始终是调用 bindFunctions
的套接字。本来以为handler socket应该和函数内部的socket是一样的
所以我有两个问题:
为什么 'my event'
函数中的套接字是调用 bindFunctions
的套接字而不是触发事件的套接字?
我该怎么做才能在函数内部访问调用 'my event'
的套接字的属性?
发生这种情况是因为尽管您在循环内执行 var socket = io.sockets.connected[socketId];
,但 in Javascript, the var
keyword is function scoped 而不是块范围。
胆量之下,真正发生的事情是:
bindFunctions(){
var socket;
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
//This is always the same property, no matter who calls this function.
});
}
}
因此,由于您的事件将在稍后发生,因此您的 socket
变量始终是最后一组。
要防止此行为,如果使用 Node.js 版本 > 4.0.0,则可以使用 const
instead of var
, because it's block scoped。但是在 Node.js 中,为了能够在块范围内使用 const
和 let
关键字,您必须将 'use strict';
放在函数的开头,例如:
bindFunctions(){
'use strict';
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
const socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
//This is always the same property, no matter who calls this function.
});
}
}
另一种解决问题的方法是创建一个 IIFE,因此您总是将当前变量传递给事件,例如:
bindFunctions(){
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
var socket = io.sockets.connected[socketId];
(function(socket) {
socket.on('my event',function(submit){
console.log(socket.myVariable);
});
})(socket);
}
}
这样做,IIFE 中的 socket
变量将始终引用作为参数传递的对象,您将获得所需的行为。
您还可以使用 Object.keys
结合 Array.prototype.forEach
而不是 for...in
循环:
bindFunctions(){
var room = io.sockets.adapter.rooms["myRoom"];
Object.keys(room).forEach(function(key) {
var socketId = room[key];
var socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
});
});
}
这样做,您将在每次迭代中创建一个新的上下文,因为它是一个被调用的回调函数,并且您不会遇到函数作用域的问题。
io.on('connection', function(socket) {
socket.join('myRoom');
if(condition){
bindFunctions();
}
});
假设第 4 个套接字连接时 condition
为真。下面的代码成功地将 .on
处理程序绑定到 myRoom
.
bindFunctions(){
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
var socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
//This is always the same property, no matter who calls this function.
});
}
}
然而,当 'my event'
触发时,无论哪个客户端触发它,socket
对象始终是连接的第 4 个套接字。它始终是调用 bindFunctions
的套接字。本来以为handler socket应该和函数内部的socket是一样的
所以我有两个问题:
为什么 'my event'
函数中的套接字是调用 bindFunctions
的套接字而不是触发事件的套接字?
我该怎么做才能在函数内部访问调用 'my event'
的套接字的属性?
发生这种情况是因为尽管您在循环内执行 var socket = io.sockets.connected[socketId];
,但 in Javascript, the var
keyword is function scoped 而不是块范围。
胆量之下,真正发生的事情是:
bindFunctions(){
var socket;
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
//This is always the same property, no matter who calls this function.
});
}
}
因此,由于您的事件将在稍后发生,因此您的 socket
变量始终是最后一组。
要防止此行为,如果使用 Node.js 版本 > 4.0.0,则可以使用 const
instead of var
, because it's block scoped。但是在 Node.js 中,为了能够在块范围内使用 const
和 let
关键字,您必须将 'use strict';
放在函数的开头,例如:
bindFunctions(){
'use strict';
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
const socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
//This is always the same property, no matter who calls this function.
});
}
}
另一种解决问题的方法是创建一个 IIFE,因此您总是将当前变量传递给事件,例如:
bindFunctions(){
for(var socketId in io.sockets.adapter.rooms["myRoom"]){
var socket = io.sockets.connected[socketId];
(function(socket) {
socket.on('my event',function(submit){
console.log(socket.myVariable);
});
})(socket);
}
}
这样做,IIFE 中的 socket
变量将始终引用作为参数传递的对象,您将获得所需的行为。
您还可以使用 Object.keys
结合 Array.prototype.forEach
而不是 for...in
循环:
bindFunctions(){
var room = io.sockets.adapter.rooms["myRoom"];
Object.keys(room).forEach(function(key) {
var socketId = room[key];
var socket = io.sockets.connected[socketId];
socket.on('my event',function(submit){
console.log(socket.myVariable);
});
});
}
这样做,您将在每次迭代中创建一个新的上下文,因为它是一个被调用的回调函数,并且您不会遇到函数作用域的问题。