0

I was going through an example explaining the use of var in a loop where there is a setTimeout:

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

logs out

10
10
10
10
10
10
10
10
10
10

The explanation is that the loop executes completely and then the setTimeout.

In the following example, setTimeout block is wrapped in an immediately-invoked function:

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

which shows

0
1
2
3
4
5
6
7
8
9

Is this because of both:

  1. An IIFE executing immediately means that even if it contained a setTimeout, the setTimeout would be executed immediately. I.e. An IIFE trumps any asynchronous code inside it and executes it immediately?

  2. The function scoping of the IIFE shadows i but creates a separate variable that tracks the value of the outer i at each iteration


EDIT (An additional question that I didn't articulate well in the original post):

Why does asynchronous code (setTimeout) execute after the loop is completed whereas in the second example it executes immediately at each iteration?

Thanks

jjkl
  • 353
  • 6
  • 15
  • 2
    It is answer 2. – CherryDT Jul 28 '20 at 13:24
  • ``i`` of outer function is pulled by setTimeout and cannot be released – iopzhu Jul 28 '20 at 13:26
  • Prints 0 1 2 3 4 5 6 7 8 9 for me in both cases –  Jul 28 '20 at 13:27
  • @super you must be using `let` or otherwise not executing *this* code. I rule out the possibility for your JavaScript engine to be non-compliant, so its not possible to get this result. [Example](https://jsbin.com/hejidu/edit?js,console) – VLAZ Jul 28 '20 at 13:29
  • It's fully compliant, I just ran it inside my time machine. –  Jul 28 '20 at 13:31
  • "*Why does asynchronous code (setTimeout) execute after the loop is completed whereas in the second example it executes immediately at each iteration?*" that's not what happens. In the second example `setTimeout` still schedules something to be executed *later* and that will *always* be after the loop finishes. [You can verify here](https://jsbin.com/liwenef/edit?js,console). With an IIFE the `i` variable is shadowed. It really doesn't need to be named `i` - in effect it's just a *different* variable. [See here](https://jsbin.com/mutuvit/1/edit?js,console) – VLAZ Jul 28 '20 at 13:47
  • @VLAZ I see. So is the sequence of execution in your example something like: for loop fully executes --> `console.log("loop finished")` --> 1st `setTimeout` execution with scoped variable of first iteration of the for loop (i.e. 0) --> 2nd `setTimeout` execution with scoped variable of second iteration of the for loop (i.e. 1) ... last `setTimeout` execution with scoped variable of last iteration of the for loop (i.e. 9)? – jjkl Jul 28 '20 at 13:55
  • Yes. With the IIFE, you get a *new* set of variables. Without it and when using a `var` what happens is that every function executes and subsequently uses *the same* `i` as every other. So with `setTimeout(function() { console.log(i); }, 100 * i);` the `100 * i` is evaluated immediately during the loop. For example, for `i = 3` you'd get `300` guaranteed. However, when the scheduled function executes, it will read the value of `i` *after* the loop finished, which would be `10`. With an IIFE, you simply get a copy of that value `3` that happens to have the same name but is not the same variable – VLAZ Jul 28 '20 at 13:59

0 Answers0