Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable scope inside loop with async call

I'm making an async call (https://github.com/socketio/socket.io-redis#redisadapterclientsroomsarray-fnfunction) with socket.io inside of a loop.

elements.forEach((element) => {
  const foo = {
    id: element.id,
    name: element.name,
  };

  // async code
  io.in(element.id).clients((err, clients) => {
    foo.clients = clients;
  });
});

Since this loop will run to completion before all the async calls complete, is there a guarantee that callback function will use the const foo declared immediately before it?

like image 374
user784637 Avatar asked Jan 30 '26 06:01

user784637


1 Answers

is there a guarantee that callback function will use the const foo declared immediately before it

TL; DR; Yes.

The reference to socket.io is irrelevant. The guarantee comes from JS itself.


Each time

const foo = { ... }

and

(err, clients) => { foo.clients = clients })

executed they're not simple declaring a variable and a function, but create a new variable and a new closure.

Probably your fears come from the common pitfall of var:

for(var i = 0 ; i != 3 ; ++i) setTimeout(() => console.log("i =", i), 0)

this will output "i = 3" tree times.

But any of the following will give you the expected result:

  1. let/const:

    for(let i = 0 ; i != 3 ; ++i) setTimeout(() => console.log("i =", i), 0)
    

    That's because let (and const) behaves differently from var. See MDN:

    let allows you to declare variables that are limited to the scope of a block statement, or expression on which it is used, unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope

  2. forEach:

    [1,2,3].forEach((v, i) => setTimeout(() => console.log("i =", i), 0) )
    

    That's because arguments of each call of forEach callback are actually different variables

  3. And even var inside a function scope:

    [1,2,3].forEach((v, i_) => { var i = i_; setTimeout(() => console.log("i =", i), 0) } )
    

    That's because var i = i_ declares a new variable local to each call of forEach callback.

    But it's not so in this case:

    for(let i_ = 0 ; i_ != 3 ; ++i_) {
      var i = i_
      setTimeout(() => console.log("i =", i), 0)
    }
    

    Because var is hoisted. So the previous code is equivalent to

    var i
    for(let i_ = 0 ; i_ != 3 ; ++i_) {
      i = i_
      setTimeout(() => console.log("i =", i), 0)
    }
    
like image 169
x00 Avatar answered Feb 01 '26 20:02

x00



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!