Introduction
JavaScript is single-threaded but handles asynchronous operations using features like callbacks, event loop, and timers. One common source of confusion for developers is using setTimeout() inside a loop—especially when the output is not what they expect.
Many beginners assume that setTimeout() executes sequentially within a loop, but due to JavaScript’s asynchronous nature and variable scope, the behavior can be surprising.
In this article, we will clearly understand why this issue happens, how it works internally, and how to fix it using modern JavaScript techniques.
What is setTimeout Inside Loop Issue?
The setTimeout inside loop issue occurs when you use setTimeout() within a loop, and all callbacks print the same value instead of the expected sequential values.
This usually happens because:
- setTimeout() executes asynchronously
- Variables declared with var are function-scoped, not block-scoped
- The loop completes before setTimeout() callbacks execute
Basic Syntax of setTimeout()
setTimeout(function, delay);
Example:
setTimeout(() => {
console.log("Hello");
}, 1000);
Show Problem in Example
Let’s see the issue:
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Expected Output:
12
3
4
5
Actual Output:
6
6
6
6
Explanation of this issue happened
I will explain step by step.
- Loop runs quickly from 1 to 5
- setTimeout() schedules callbacks
- Loop finishes → i becomes 6
- After 1 second, callbacks execute
- All callbacks reference same i → 6
Note: Because var is function-scoped, not block-scoped.
Solutions of this issue
Solution 1: Use let (Best & Modern Way)
for (let i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
Output:
2
3
4
5
Note: let is block-scoped, so each iteration gets its own value.
Solution 2: Using IIFE (Closure)
Creates a new scope for each iteration.
for (var i = 1; i <= 5; i++) {
(function (x) {
setTimeout(function () {
console.log(x);
}, 1000);
})(i);
}
Solution 3: Using setTimeout with Parameter
for (var i = 1; i <= 5; i++) {
setTimeout(function (i) {
console.log(i);
}, 1000, i);
}
Real-Life Example of Showing Notifications One by One
❌ Wrong Way:
for (var i = 1; i <= 3; i++) {
setTimeout(() => {
console.log("Notification " + i);
}, i * 1000);
}
Output:
Notification 4
Notification 4
✅ Correct Way:
for (let i = 1; i <= 3; i++) {
setTimeout(() => {
console.log("Notification " + i);
}, i * 1000);
}
Output:
Notification 2
Notification 3
Common Mistakes when using setTimeout Inside a Loop
There are some common mistakes when using setTimeout inside a Loop.
1. Using var instead of let
for (var i = 0; i < 5; i++) { }
2. Assuming setTimeout is synchronous
console.log("Start");
setTimeout(() => console.log("Middle"), 1000);
console.log("End");
Output:
End
Middle
3. Ignoring Event Loop behavior
JavaScript executes
- Call Stack
- Web APIs
- Callback Queue
- Event Loop
4. Wrong delay assumptions
for (let i = 1; i <= 5; i++) {
setTimeout(() => console.log(i), 1000);
}
Note: In this example, all run after 1 second, not sequentially.
Interview Questions
Q 1: What is the setTimeout inside loop issue?
Q 2: Why does var cause problems?
Q 3: How does let fix the issue?
Q 4: Can we solve it without let?
IIFE
setTimeout parameters
Q 5: What is the event loop?
Conclusion
In this tutorial, you learned how JavaScript handles asynchronous code and variable scoping. While it may seem confusing at first, once you understand concepts like event loop, closures, and block scope, it becomes much easier to handle.