1

What is the logic behind the IIFE function and the logic behind setTimeout() in a loop. There are two for:

for (var i = 0; i < 10; i++) {
  // Standard
  setTimeout(function() {
    console.log("Standard" + i);
  }, 1000 * i);
}

for (var j = 0; j < 10; j++) {
  // IIFE
  (function(j) {
    setTimeout(function() {
      console.log("IIFE " + j);
    }, 1000 * j);
  })(j);
}

Now when I run with node.js, I have this result after 10 seconds (each console.log() is executed every second):

PowerShell

Can someone explain to me the runtime logical difference between the invocation of the first function and the second ?

Especially if you can answer these questions:

  • Why the log is executed each second in both for? (1000 * i|j is ignored)
  • Why the value of i always 10?

Thank you in advance.

[Edit] I don't understand why in both for the console.log() is fired every second but the timeout seconds 1000 * i|j may be a visible timeout.

Alberto Favaro
  • 1,824
  • 3
  • 21
  • 46
  • 1
    Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – VLAZ Apr 03 '18 at 08:53
  • Possible duplicate of [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – dloeda Apr 03 '18 at 08:55
  • You've ran the loop 10 times, by the time the setTimeout executes `i` is equal to 10, a closure in the second loop passes the value to the function hence why the other setTimeout remembers the correct number. – Adrian Apr 03 '18 at 08:55
  • Unless you're doing this for some educational/experimental purposes, you should really just use `let` when initializing the variable in the for loop. – maazadeeb Apr 03 '18 at 08:56
  • Without the IIFE the variable is a reference because you used `var`, thanks the IIFE the current value is captured.Try `let` instead of `var` and you will be surprise – GameTag Apr 03 '18 at 09:02
  • Its all about callback and method call stack, read the differences between these 2 you will get the answer. – Sunil Sharma Apr 03 '18 at 09:12
  • What makes you think that "*1000 * i|j is ignored*"? If you had instead put a constant timeout value, all the callbacks would have run at the same time – Bergi Apr 03 '18 at 09:24
  • I don't understand why the `setTimeout()` milliseconds is ignored in both `for`. Becouse the result of `1000 * i` is a "visible" timeout but `console.log()` is fired every second – Alberto Favaro Apr 03 '18 at 09:25
  • OK, why isn't this closed as a duplicate yet? Also `I don't understand why in both for the console.log() is fired every second but the timeout seconds 1000 * i|j may be a visible timeout.` - have you checked the dupe? The `i` *inside* that gets printed is the last `i` you got after the loop end. The `i` on the *outside* which you pass into the `setTimeout` is the current `i` from the loop. This should become apparent when looking at the dupes linked. – VLAZ Apr 03 '18 at 09:56

2 Answers2

1

Why the log is executed each second in both for? (1000 * i|j is ignored)

This is because setTimeout() is an asynchronous function. So the execution does not get blocked at this step, rather a clock is started with the given time duration parameter and the execution moves on. Once the duration is passed, events are fired and the callback is added to the event loop queue for being executed one by one.

Why the value of i always 10?

This is because of the concept of closure. When the first "Standard" timeouts, the value of i by that time is already 10 (All setTimeouts are registered by then). While in the case of IIFE, j is a formal parameter in the function that receives the loop counter variable value after each iteration. And the setTimeouts contained in this function uses this j.

Anurag Lal
  • 103
  • 7
0

In the first version setTimeout is referencing the variable i from the parent scope when it fires, but by then it has already changed.

In the second you create a bunch new scope with a j parameter that is not a reference to the parent scopes j variable. Therefore it is unchanged when the setTimeout fires.

Emil S. Jørgensen
  • 6,216
  • 1
  • 15
  • 28