0

I'm trying to figure out why this script doesn't increment the timeout by i, which is what I'd expect it to do:

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

This just logs 10, ten times. setTimeout should have access to i, as should the function, from what I can tell. Still, it doesn't work as I expect it to.

Here is a fiddle

Fares M.
  • 1,538
  • 1
  • 17
  • 18

2 Answers2

1

The issue is that by the time the inner function gets executed, the value of i is 10, that's why you're getting 10, 10 times.

Closures 'close' over variables not over values. This means that the closure (the function inside the setTimeout) has access to the variable at the time it executes no to the value of the variable when the closure was created.

So effectively you are executing the following code:

var i;
for(i=0; i<10; i++ ){
}

// delay 0ms
console.log(i);
// some delay 
console.log(i);
// some delay 

....

Also remember that JS is a single threaded language, so the first setTimeout can't execute until you "yield", that means that the first function inside the setTimeout only executes when the for loop finishes, it doesn't matter how small a delay you specify in the setTimeout

Jaime
  • 6,736
  • 1
  • 26
  • 42
  • Thanks for your answer. I want to accept this, but "*Closures 'close' over variables not over values.*" is very vague to me. Could you elaborate on that a little? – vkjb38sjhbv98h4jgvx98hah3fef Apr 18 '15 at 07:59
  • Also, is this not also partially a race condition? I've read that the minimum `setTimeout` delay is 4ms (https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout#Notes). Does this mean that the for loop finishes within 4ms, and thereby sets `i = 10` for all exexuted code? – vkjb38sjhbv98h4jgvx98hah3fef Apr 18 '15 at 08:05
  • see edits for both comments – Jaime Apr 18 '15 at 18:14
0

You need to understand about closure. Here's the solution to your problem:

for( var i=0; i<10; i++ ){
  (function(i){
    setTimeout( function(){
        console.log( i );
    }, i*10 );
  })(i);
}
Hoyen
  • 2,511
  • 1
  • 12
  • 13