JavaScript is Awesome!If you’ve ever programmed something in JavaScript, you most likely ran into a situation where you needed a delay.

Normally, we do this with setTimeout().

For repeatedly calling some function every X milliseconds, one would normally use setInterval().

Well, that’s fine. But what if you want to so something 10 times, and delay 3 seconds between iterations?

The solution is not as obvious as it appears…

But it is simple!

We’re going to just use the following code as our “function”:

alert("Cheese!");

Normally you would probably want to do something a bit more complicated than that, but we’ll just keep things simple for the sake of the example.

Now, most likely, in order to alert “Cheese!” ten times (with a 3-second delay between each alert), the first thing you’ll probably try is this:

for (var i = 1; i < 10; i++) {
  setTimeout(function () {
    alert("Cheese!");
  }, 3000);
}

The above code will not do what you want, though. JavaScript executes linearly, one line after another. But it also has a stack, or a queue of operations to perform. The code works like so:

  1. The setTimeout function is queued immediately for future execution (after 3 seconds)
  2. The for loop moves on to the next iteration right away
  3. The setTimeout function is again queued immediately for future execution (after 3 seconds)

… and so on, up to 10 times.

So, what’s the problem?

Well, the queuing of the setTimeout function and the for loop iterations happen “instantly”, or nearly so. That means that within milliseconds, all 10 of your alert(“Cheese!”); functions are queued up and ready to fire – one after the other, about 3 seconds in the future.

Instead of seeing 1 alert message every 3 seconds, what you get is a 3-second delay followed by 10 alert messages in quick succession!

Visually, you’re getting this:

The Wrong WayAnd that’s not what you want. So, what to do?

Behold:

(function theLoop (i) {
  setTimeout(function () {
    alert("Cheese!");
    if (--i) {          // If i > 0, keep going
      theLoop(i);       // Call the loop again, and pass it the current value of i
    }
  }, 3000);
})(10);

First of all, we’re using a self-invoking function. The last line calls the function theLoop, and passes it the value 10 for i.

Next, the setTimeout function will call the code inside after 3 seconds have passed. But notice the code included after the alert

There is a check that says if we decrement i, and it’s still greater than 0, we should call theLoop(i) again. Note that this if statement and the subsequent calling of theLoop is not queued instantly, because all the code inside the setTimeout will only execute after 3 seconds has elapsed. So, this code works like so:

  1. The setTimeout function is queued immediately for future execution (after 3 seconds)
  2. After 3 seconds, the alert fires, we decrement i, and we call theLoop again, which queues the next setTimeout function

… and so on, up to 10 times.

That’s exactly what we want: 10 alerts, and each alert pops up 3 seconds after the previous one.

Ta-DA!

If you’d like to get really fancy, you can do this:

(function theLoop (data, stuff, i) {
  setTimeout(function () {
    alert("Cheese!");
    // DO SOMETHING WITH data AND stuff
    if (--i) {                  // If i > 0, keep going
      theLoop(data, stuff, i);  // Call the loop again
    }
  }, 3000);
})(data, stuff, i);

If any of this is confusing, or if you’d really like to understand more about some of the pitfalls and complexities of JavaScript, you seriously need to read K. Scott Allen’s excellent explanations of things like this, Function.apply vs. Function.call, variable scopes, and closures in JavaScript:

And finally, don’t miss John Resig on How Javascript Timers Work!

Need help? Hire me!
Get Scottie Stuff!