1

I'm writing a for loop in Javascript. The desired goal is to print out 0, 1, 2 with a 3 second gap in between.

for (var i=0; i<3; i++) {
    console.log(i);
}

This prints everything out as expected, with no pause. But when I add in a setTimeout:

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

The result is that it prints out 3, 3, 3 with a 3 second gap. The pause worked, but it looks like its completing the loop before the right numbers can get printed.

Morgan Allen
  • 3,291
  • 8
  • 62
  • 86

1 Answers1

4

You're exactly right that the loop is getting completed before the setTimeout calls run. Since all of your timeout functions reference i, they're all going to print out 3. The way to fix this is to capture the value of i in a closure.

for (var i = 0; i < 3; i++) {
  (function(index) {
    setTimeout(function() {
      console.log(index);
    }, 3000 * index);
  })(i); // Instantly call the function and pass the value of i
}
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
  • Or you could use the `.bind()` method -> http://jsfiddle.net/jb9pd5ub/ – Josh Crozier Dec 10 '15 at 21:33
  • @JoshCrozier That would definitely work as well. – Mike Cluck Dec 10 '15 at 21:35
  • I'm new to Javascript and had a follow up question. The context is that I have a list of URL's that I want to click (but not all at the same time, and thus the pause). How do I set `index` and what do you mean `Instantly call the function and pass the value of i`? That part didn't make sense to me. – Morgan Allen Dec 10 '15 at 21:43
  • btw, this works, but I don't understand how `index` is getting set to the value of `i` and what `(i)` is doing :-) – Morgan Allen Dec 10 '15 at 21:53
  • `(i)` is the argument of the "immediately invoked function expression", that means you ar calling `(function(index) { ..... }` with parameter `i`. The value of index (i) is then preserved within the local scope of the function passed to the setTimeout, the closure. – wiredolphin Dec 10 '15 at 22:26