for-Loop with Delay in JavaScript

Update November 2016:

While this post is still valid for ES5, I wanted to point out that there is now an easier method using async/await in the latest TypeScript 2.1.0 release. You can use this feature natively in the latest Node version, but TypeScript now allows you to compile async/await to ES5 for browsers.

You should still read the original post, especially if you found this blog entry while googling a similar problem.

const delay = (amount: number) => {
  return new Promise((resolve) => {
    setTimeout(resolve, amount);

async function loop() {
  for (let i = 0; i < 50; i++) {
    await delay(100);


Original Post

I've had multiple JavaScript beginners ask me this how they can create a for-loop with delay. This code is what most have come up with (for quick readers: not what you are looking for!):

for (var index = 1; index < 50; index++) {
    setTimeout(function() {
    }, 100);    

Now this prints "50" fifty times, because a for-loop is synchronous while setTimout is asynchronous. This means that the for-loop is finished very fast and has started 50 setTimeouts. After 100ms all of those setTimeout functions will fire together, therefore printing "50" fifty times. Note that the var-keyword binds variables to the function scope, not the current block scope like in other languages.

In order to create a for-loop with actual delay - in our case printing a number, waiting 100ms and printing the next number - you need to create a self-invoking, recursive function. Don't worry, it's not that hard.

var maxLoops = 50;
var counter = 0;

(function next() {
    if (counter++ > maxLoops) return;

    setTimeout(function() {
    }, 100);

Here we declare two variables, maxLoops and counter. These are for keeping track of how many times the function has called itself. Afterwards we create the function "next", put it in brackets and call it immediately. This is why it's called a self-invoking function.

The if-statement does two things. First of all it counts up our counter variable using the ++ operator. It also returns the function if it has been called 50 times, therefore stopping the loop.

The last part is the most important one. We create our setTimeout function and then call next() after the number has been printed. And that's how you create a for-loop with delay in JavaScript.

Here is an even shorter, but harder to understand solution:

(function next(counter, maxLoops) {
    // break if maxLoops has been reached
    if (counter++ > maxLoops) return;

    setTimeout(function() {

        // call next() recursively
        next(counter, maxLoops);
    }, 100);
})(0, 50);

9 thoughts on “for-Loop with Delay in JavaScript

  1. Tony

    Thanks for this Patrick? What about with multiple variables? I’m trying to do something with colors (vars r, g, b) and want to change the background color of the page gradually, from (0,0,0) to (255,255,255) with .5 second delay between each update.

  2. Tobi P.

    Hoi Patrick

    I was searching this specific question on google and was very amused to see, that this blog-entry was the second highest ranked result!

    Very nice written description of a solution which really helped me.

    Gruess us Büüre

  3. mate

    Hey, after few days of searching for a very specific problem I found this kind of solution and something i banged my head for a while runs smoothly now. Thank you very much 🙂

  4. Etienne

    I know i’m a bit late but still I’d like to thank you for this, this was really helpful !

    It’s been a while since I’ve been looking for something like this and for once, stackoverflow wasn’t really helpful with providing a clear explanation as you did.

    There is two things I didn’t quite understand tho, why is the next Function between parens and what are the last parens for ?

    1. Patrick Muff Post author

      The last two parenthesis are to immediately call the next function. This is only possible because we wrapped the next function into parenthesis itself.


Leave a Reply

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