Brent Aureli
Brent Aureli

Reputation: 473

Callback function missing scope for required data

I have a issue with a callback function's variable losing its scope

. I have the following 2 objects in an array(simplified down to show the problem)

const search = [{socket: new WebSocket('ws://live.trade/123')}, 
                {socket: new WebSocket('ws://live.trade/xyz')}];

I then do a forEach on them in an attempt to log the sockets url once the socket is open.

search.forEach(function(element){
    element.socket.on('open', function open() {
      console.log(element.socket.url);
    });
});
*actual output*
ws://live.trade/xyz
ws://live.trade/xyz

*expected*
ws://live.trade/123
ws://live.trade/xyz

I feel like the reason is that when the function open() runs element is not in scope and it just uses whatever was last there(being the ws://live.trade/xyz). Is this correct? And finally what would be the way to go about fixing this? The real use for this is when the socket is opened I need to send version data to the server via the socket that called it... Im going to have many sockets in reality and dont want to write a "socket.on('open'...)" for each individual one.

Any suggestions?

Thanks so much!

Upvotes: 2

Views: 213

Answers (1)

xdrm
xdrm

Reputation: 399

Your callback (i.e. in socket.on()) uses the element variable of the forEach(). From your actual result, it could mean that:

1. Scope issue

The variable could be "overriden" over the iterations because of javascript/node scope mechanism, it is not the case with the code you gave but it is a common issue working with scopes inside loops.

in this case you would have to do :

search.forEach(function(element){
    element.socket.on('open', function(){
      console.log(this.socket.url);
    }.bind(element));
});

Explanation:

  • bind() passes its first argument (the element variable in this case) to the anonymous function as this inside it.
  • Inside your callback function, this.socket is equivalent to element.socket at the appropriate iteration

[UPDATE] after pointed out by Felix Kling, forEach() provides a scope for each element.

See bind for more details.

2. Dependency issue

If it is not a scope issue, it could mean that the library you are using does not work as expected. Maybe, try to log element inside the forEach() to check if the WebSocket objects are what you expect.

edit

  • For further reading on node/js loops and reference: see here
  • For node/js closures in general: see here

Upvotes: 1

Related Questions