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();
I have created a set of resources for learning asynchronous JavaScript. These guides—Callbacks, Promises, and Async/Await —cover everything I’ve learned from years of real-world JavaScript experience.
If you found this article helpful, you’ll get so much out of these guides. Each one is optimized for those “lightbulb moments,” building a strong mental model for how asynchronous JavaScript works and how you can use it to create fast, dynamic applications.