1 July 2014

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!

JavaScript Fun: Looping with a Delay
Tagged on:         

5 thoughts on “JavaScript Fun: Looping with a Delay

  • 4 February 2016 at 17:41
    Permalink

    Awesome tutorial that made my day! Thought that was happening with the que but wasn’t sure how to fix.

    Reply
  • 23 March 2016 at 13:56
    Permalink

    Hi
    Thank you for this tutorial.
    I kind of got it but it quickly turned into a mess in my head.
    So I implemented it “the hacking way” into my code and it performed like a charm. (even though I had to mark the perimeter of this code with “don’t touch” comments)

    Now the time to pay the technical dept is coming, as I have to turn this code into Java for I am porting my mini game on smartphone 🙂

    As far as I got, the answer is ” Thread.sleep ” but I have a feeling it is not what I am looking for.

    Could you show me the direction to the Java way of this tutorial ?

    thx again 🙂

    Reply
    • 23 March 2016 at 15:08
      Permalink

      EEK!! I haven’t programmed anything in Java in a loooong time. I’m afraid I can’t help you there.

      Reply
  • Pingback: Tic-Tac-Toe, Simon says…no. FreeCodeCamp | Codey McCodeface

  • 19 December 2017 at 21:15
    Permalink

    Very well written and explained. Thank you!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.