Why setTimeout Doesn't Work in Loops: Results Coming Together After Timeout
You're trying to make "Hello" appear after a 5-second delay, and you want it to happen 10 times. You created a function called printHello
with a 5-second delay using setTimeout
, and then you ran this function 10 times in a loop.
Here's the code:
function printHello() { setTimeout(function () { console.log("Hello"); }, 5000); } for (let i = 0; i < 10; i++) { printHello(); }
However, you notice that all the "Hello" messages are printed together after 5 seconds.
The question is, why doesn't setTimeout
work as expected in a loop?
Loops operate synchronously, meaning they go through all their iterations effectively "at once." In this case, each printHello()
in the loop is getting called simultaneously, one after the other. Consequently, each function starts its 5-second timer at the same time, leading to all the timers ending simultaneously.
There are several ways to address this.
1. Use setInterval
One way is to use setInterval()
. When you call it once, it keeps running a function repeatedly every few milliseconds.
You'd need to keep track of how many times it runs, and then call clearInterval()
when it's over to stop the looping.
let counter = 0; const intervalId = setInterval(function () { console.log("Hello"); counter++; if (counter === 10) { clearInterval(intervalId); // Stop the interval after 10 iterations } }, 5000);
This way, the callback inside setInterval
will be executed every 5 seconds, and you can control the number of iterations by incrementing the counter
variable and clearing the interval when the desired count is reached.
2. Use the Loop Variable to Manage Delays
Utilize the loop variable to determine the delay for each function call. Adjust the delay by multiplying the loop variable with the desired time interval. In this case, the code could look like this:
function printHello() { console.log("Hello"); } for (let i = 1; i <= 10; i++) { setTimeout(function () { printHello(); }, i * 5000); }
3. Controlled Delays Using async
and await
Transform your functions into async
functions and leverage the await
keyword along with the provided sleep
function for controlled delays:
let sleep = (dur) => new Promise((res) => setTimeout(res, dur)); async function runLoop() { for (let i = 0; i < 10; i++) { console.log("Hello"); await sleep(500); // Wait for 500 milliseconds } } // Call the async function to start the loop runLoop();
Get my free, weekly JavaScript tutorials
Want to improve your JavaScript fluency?
Every week, I send a new full-length JavaScript article to thousands of developers. Learn about asynchronous programming, closures, and best practices — as well as general tips for software engineers.
Join today, and level up your JavaScript every Sunday!
Thank you, Taha, for your amazing newsletter. I’m really benefiting from the valuable insights and tips you share.