How do I add a delay in a JavaScript loop?

Viewed 673735

I would like to add a delay/sleep inside a while loop:

I tried it like this:

alert('hi');

for(var start = 1; start < 10; start++) {
  setTimeout(function () {
    alert('hello');
  }, 3000);
}

Only the first scenario is true: after showing alert('hi'), it will be waiting for 3 seconds then alert('hello') will be displayed but then alert('hello') will be repeatedly constantly.

What I would like is that after alert('hello') is shown 3 seconds after alert('hi') then it needs to wait for 3 seconds for the second time alert('hello') and so on.

32 Answers

You can create a sleep function that promisifies setTimeout. This enables you to use async/await to write code without callbacks and the familiar for loop control flow.

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

(async () => {
  for (let i = 0; i < 10; i++) {
    console.log(i);
    await sleep(1000);
  }

  console.log("done");
})();

In Node, you can use timers/promises to avoid the promisification step (if the feature isn't supported on your older Node version, the above code works just as well):

const {setTimeout: sleep} = require("timers/promises");

// same code as above

Regardless, since JS is single-threaded, it's a good thing that timeouts are asynchronous. If they weren't, the browser wouldn't get a chance to repaint the UI, leading to a frozen interface for the user.

In my opinion, the simpler and most elegant way to add a delay in a loop is like this:

names = ['John', 'Ana', 'Mary'];

names.forEach((name, i) => {
 setTimeout(() => {
  console.log(name);
 }, i * 1000);  // one sec interval
});

In ES6 you can do as following:

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

In ES5 you can do as:

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

The reason is, let allows you to declare variables that are limited to a scope of a block statement, or expression on which it is used, unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

A function-less solution

I am a bit late to the party, but there is a solution without using any functions:

alert('hi');

for(var start = 1; start < 10; start++) {
  setTimeout(() => alert('hello'), 3000 * start);
}

To my knowledge the setTimeout function is called asynchronously. What you can do is wrap the entire loop within an async function and await a Promise that contains the setTimeout as shown:

var looper = async function () {
  for (var start = 1; start < 10; start++) {
    await new Promise(function (resolve, reject) {
      setTimeout(function () {
        console.log("iteration: " + start.toString());
        resolve(true);
      }, 1000);
    });
  }
  return true;
}

And then you call run it like so:

looper().then(function(){
  console.log("DONE!")
});

Please take some time to get a good understanding of asynchronous programming.

In addition to the accepted answer from 10 years ago, with more modern Javascript one can use async/await/Promise() or generator function to achieve the correct behavior. (The incorrect behavior suggested in other answers would be setting series of 3 seconds alerts regardless of "accepting" the alert() - or finishing the task at hand)

Using async/await/Promise():

alert('hi');

(async () => {
  for(let start = 1; start < 10; start++) {
    await new Promise(resolve => setTimeout(() => {
      alert('hello');
      resolve();
    }, 3000));
  }
})();

Using a generator function:

alert('hi');

let func;

(func = (function*() {
  for(let start = 1; start < 10; start++) {
    yield setTimeout(() => {
      alert('hello');
      func.next();
    }, 3000);
  }
})()).next();

Just try this

 var arr = ['A','B','C'];
 (function customLoop (arr, i) {
    setTimeout(function () {
    // Do here what you want to do.......
    console.log(arr[i]);
    if (--i) {                
      customLoop(arr, i); 
    }
  }, 2000);
})(arr, arr.length);

Result

A // after 2s
B // after 2s
C // after 2s

Dead-simple, one-line solution with an actual async-await delay (no queued setTimeout):

The following (self-executing anonymous) function creates an actual delay between loops, instead of multiple setTimeouts with different timeouts, which might mess up memory.

  • In each of the 100 loops, it awaits for a new Promise to resolve.
  • This happens only after setTimeout 'allows' it after 90ms. Until then, code is blocked by the async-await / pending Promise.

(async () => {
  for (let i=0; i<100; i++) {
    await new Promise((resolve) => {setTimeout(() => {document.write(`${i} `); resolve(true)}, 90)});
  }
})()

Here is how I created an infinite loop with a delay that breaks on a certain condition:

  // Now continuously check the app status until it's completed, 
  // failed or times out. The isFinished() will throw exception if
  // there is a failure.
  while (true) {
    let status = await this.api.getStatus(appId);
    if (isFinished(status)) {
      break;
    } else {
      // Delay before running the next loop iteration:
      await new Promise(resolve => setTimeout(resolve, 3000));
    }
  }

The key here is to create a new Promise that resolves by timeout, and to await for its resolution.

Obviously you need async/await support for that. Works in Node 8.

   let counter =1;
   for(let item in items) {
        counter++;
        setTimeout(()=>{
          //your code
        },counter*5000); //5Sec delay between each iteration
    }
const autoPlayer = (arr = [1, 2, 3, 4, 5]) => {
  // Base case:
  if (arr.length < 1) return

  // Remove the first element from the array.
  const item = arr.shift()

  // Set timout 
  setTimeout(() => {
    console.log('Hello, world!', item)  // Visualisation.
    autoPlayer() // Call function again.
  }, 1000) // Iterate every second.
}

Hey, I know this post is very old, but this code "loops" and adds a delay to it using a recursive method. I don't think you can 'actually' delay a loop itself from iterating based on reading various comments from other people. Maybe this can help someone out! Basically the function accepts an array (in this example). On each iteration the setTimeout Javascript method is called. The function calls itself again indefinitely when the timer of the setTimeout function expires, but on each call the array becomes smaller until it reaches the base-case. I hope this can help anyone else out.

<!DOCTYPE html>
<html>
<body>

<button onclick="myFunction()">Try it</button>

<p id="demo"></p>

<script>
function myFunction() {
    for(var i=0; i<5; i++) {
     var sno = i+1;
        (function myLoop (i) {          
             setTimeout(function () {   
              alert(i); // Do your function here 
             }, 1000*i);
        })(sno);
    }
}
</script>

</body>
</html>

Try this...

var icount=0;
for (let i in items) {
   icount=icount+1000;
   new beginCount(items[i],icount);
}

function beginCount(item,icount){
  setTimeout(function () {

   new actualFunction(item,icount);

 }, icount);
}

function actualFunction(item,icount){
  //...runs ever 1 second
 console.log(icount);
}

You do it:

console.log('hi')
let start = 1
setTimeout(function(){
  let interval = setInterval(function(){
    if(start == 10) clearInterval(interval)
    start++
    console.log('hello')
  }, 3000)
}, 3000)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Simple implementation of showing a piece of text every two seconds as long the loop is running.

for (var i = 0; i < foo.length; i++) {
   setInterval(function(){ 
     console.log("I will appear every 2 seconds"); 
   }, 2000);
  break;
};
Related