2

I have a socket.io server that generates many events, and I want to catch all of them and print a similar message. Right now, I do this:

for (var event in {eventA: 1, eventB: 1, eventC: 1}) {
    this.translationSocket.on(event, function(result) {
        console.log("Server sent an event of type "+event);
    });
}

When the server sends eventA, eventB and eventC, I see this:

Server sent an event of type eventC
Server sent an event of type eventC
Server sent an event of type eventC

i.e. my program catches all events, but always displays the type of eventC...

I tried the following variations:

  • remove the "var" before the "event" inside the "for": "for (event ..."
  • adding a statement 'var msg = "Server sent an event of type "+event;' either before the 'on' statement or just before the 'console.log' statement, and then 'console.log(msg)'.

None of these variations worked...

What should I do?

Salvatorelab
  • 11,614
  • 6
  • 53
  • 80
Erel Segal-Halevi
  • 33,955
  • 36
  • 114
  • 183

3 Answers3

1

This has nothing to do with socket.io or node.js, this is well known JavaScript "quirk". The value of event is evaluated when the code is executed, which is when the loop is finished. You need to wrap thing into a function call to preserve the value.

var listen = function(socket, event) {
    socket.on(event, function(result) {
        console.log("Server sent an event of type "+event);
    });
}


for (var event in {eventA: 1, eventB: 1, eventC: 1}) {
    listen(event);
}

Or (shorter version):

for (var event in {eventA: 1, eventB: 1, eventC: 1}) {
    (function(event) {
        this.translationSocket.on(event, function(result) {
            console.log("Server sent an event of type "+event);
        });
    })(event);
}
Erel Segal-Halevi
  • 33,955
  • 36
  • 114
  • 183
TheHippo
  • 61,720
  • 15
  • 75
  • 100
1

In for (var event in ...) you're declaring a variable and because of the variable scope rules in JavaScript it will be valid outside of the foreach loop.

The event variable becomes eventC at the end of the loop. So it's value, when you want to print it will be eventC.

You can do something like this:

function generateCallback(e, result) {
    return function () {
        console.log("Server sent an event of type " + e);
    };
}

var e;
// ...
for (e in {eventA: 1, eventB: 1, eventC: 1}) {
    this.translationSocket.on(e, generateCallback(e, result));
}

To prevent confusion you'd better not to declare variables in for statements.

And also it's better, not to make functions within a loop. That's why I used generateCallback instead of making a callback function within the loop.

Community
  • 1
  • 1
fardjad
  • 20,031
  • 6
  • 53
  • 68
0

I would use socket.io-events on npm. You can capture all events and handle them however you want without having to bind separate handlers.

var io = require('socket.io')(3000);
var router = require('socket.io-events')();
 router.on('*', function (sock, args, next) {
 var name = args.shift(), msg = args.shift();
 sock.emit('received event', name, msg);
});
io.use(router);
Nathan Romano
  • 7,016
  • 3
  • 19
  • 18