JavaScript is single-threaded. That means it can only do one thing at a time. So how does it handle asynchronous operations like setTimeout
, fetch
, or Promise
? The answer lies in the Event Loop.
1. The Call Stack
JavaScript executes code line by line in the call stack. Once a function finishes, it gets popped off the stack. Simple enough — but async tasks can’t block the stack forever.
2. The Event Loop
The Event Loop is like a traffic cop. It constantly checks:
- Is the call stack empty?
- If yes, are there any pending tasks waiting in queues?
If so, it pushes them into the stack for execution.
3. Task Queues
Not all tasks are equal. They are divided into Macrotasks and Microtasks.
🔹 Macrotasks
- Examples:
setTimeout
,setInterval
,setImmediate
, DOM events - They are scheduled in the Macrotask queue.
- Executed one per loop iteration.
🔹 Microtasks
- Examples:
Promise.then
,process.nextTick
(Node.js),MutationObserver
- Stored in the Microtask queue.
- All microtasks are executed before the event loop continues to the next Macrotask.
4. Example in Action
console.log("Start");
setTimeout(() => console.log("Macrotask: setTimeout"), 0);
Promise.resolve().then(() => console.log("Microtask: Promise"));
console.log("End");
Output:
Start
End
Microtask: Promise
Macrotask: setTimeout
👉 Even though setTimeout
was given 0ms
, the Promise runs first because microtasks have higher priority.
5. Why It Matters
- Misunderstanding this order can cause hard-to-debug async issues.
- Knowing it helps optimize performance, avoid race conditions, and write predictable async code.
6. Key Takeaways
- JavaScript runs one task at a time (single-threaded).
- Event Loop decides what runs next.
- Microtasks > Macrotasks in priority.
- Promises resolve before timers.
⚡ Mastering the Event Loop is not trivia — it’s critical to writing reliable async JavaScript.
Top comments (0)