将函数绑定到多个套接字(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的套接字。 我原以为处理程序套接字应该与函数内的套接字相同。

所以我有两个问题:

为什么'my event'的套接字函数是调用bindFunctions而不是触发事件的套接字的套接字?

我能做什么才能在函数内部访问调用'my event'的套接字属性?

io.on('connection', function(socket) { socket.join('myRoom'); if(condition){ bindFunctions(); } });

Let's say condition is true when the 4th socket connects. The code below successfully binds a .on handler to all the sockets in 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. }); } }

However, when 'my event' fires, regardless of which client triggered it, the socket object is always the 4th socket that connected. It is always the socket that called bindFunctions. I would have thought that the handler socket should be the same as the socket inside the function.

So I have two questions:

Why is the socket inside the 'my event' function the socket that called bindFunctions instead of the socket that fired the event?

What can I do instead to be able to access properties of the socket that called 'my event' whilst inside the function?

最满意答案

这是因为虽然你正在做var socket = io.sockets.connected[socketId]; 在循环内部, 在Javascript中, var关键字是函数作用域 ,而不是块作用域。

在胆量下,真正发生的是:

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而不是var ,因为它是块作用域 。 但是在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); }); }); }

这样做,你每次迭代都会创建一个新的上下文,因为它是一个被调用的回调函数,你不会遇到函数作用域的问题。

That happens because although you're doing var socket = io.sockets.connected[socketId]; inside the loop, in Javascript, the var keyword is function scoped, and not block scoped.

Under the guts, what really happens is:

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. }); } }

So, since your event will happen later, your socket variable is always the last one set.

To prevent this behavior, if using Node.js version > 4.0.0, you can use const instead of var, because it's block scoped. But in Node.js, to be able to use const and let keywords block-scoped, you must put 'use strict'; in the begining of your function, e.g:

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. }); } }

Another way of solving your problem is by creating an IIFE, so you always pass the current variable to the event, e.g:

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); } }

Doing that, the socket variable inside the IIFE will always refer to the object passed as parameter, and you'll get your desired behavior.


You can also use Object.keys combined with Array.prototype.forEach instead of for...in loop:

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); }); }); }

Doing that, you're creating a new context each iteration, since it's a callback function being called, and you won't have problems with function scoping.

更多推荐