How do I add a delay in a JavaScript loop?
The setTimeout()
function is non-blocking and will return immediately. Therefore your loop will iterate very quickly and it will initiate 3-second timeout triggers one after the other in quick succession. That is why your first alerts pops up after 3 seconds, and all the rest follow in succession without any delay.
You may want to use something like this instead:
var i = 1; // set your counter to 1function myLoop() { // create a loop function setTimeout(function() { // call a 3s setTimeout when the loop is called console.log('hello'); // your code here i++; // increment the counter if (i < 10) { // if the counter < 10, call the loop function myLoop(); // .. again which will trigger another } // .. setTimeout() }, 3000)}myLoop(); // start the loop
You could also neaten it up, by using a self invoking function, passing the number of iterations as an argument:
(function myLoop(i) { setTimeout(function() { console.log('hello'); // your code here if (--i) myLoop(i); // decrement i and call myLoop again if i > 0 }, 3000)})(10); // pass the number of iterations as an argument
Since ES7 theres a better way to await a loop:
// Returns a Promise that resolves after "ms" Millisecondsconst timer = ms => new Promise(res => setTimeout(res, ms))async function load () { // We need to wrap the loop into an async function for this to work for (var i = 0; i < 3; i++) { console.log(i); await timer(3000); // then the created Promise can be awaited }}load();
When the engine reaches the await
part, it sets a timeout and halts the execution of the async function
. Then when the timeout completes, execution continues at that point. That's quite useful as you can delay (1) nested loops, (2) conditionally, (3) nested functions:
async function task(i) { // 3 await timer(1000); console.log(`Task ${i} done!`);}async function main() { for(let i = 0; i < 100; i+= 10) { for(let j = 0; j < 10; j++) { // 1 if(j % 2) { // 2 await task(i + j); } } }} main();function timer(ms) { return new Promise(res => setTimeout(res, ms)); }
While ES7 is now supported by NodeJS and modern browsers, you might want to transpile it with BabelJS so that it runs everywhere.
If using ES6, you could use a for loop to achieve this:
for (let i = 1; i < 10; i++) { setTimeout(function timer() { console.log("hello world"); }, i * 3000);}
It declares i
for each iteration, meaning the timeout is what it was before + 1000. This way, what is passed to setTimeout
is exactly what we want.