Restaurant
The chef does not wait 20 minutes for pizza. Staff handles slow work in the background, and the manager brings it back when the counter is free.
Understand how JavaScript stays responsive while handling timers, API requests, promises, and user interactions.
The Event Loop continuously checks whether the Call Stack is empty. When it is free, JavaScript runs pending Microtasks first, then Macrotasks, so slow work does not freeze the page.
JavaScript is single-threaded, which means it executes one piece of code at a time. The Event Loop is the mechanism that lets JavaScript continue working while slow operations happen in the background. When those operations are ready, the Event Loop brings their callbacks back only when the Call Stack is empty.
Call Stack
Where JavaScript runs the current line or function.
Browser APIs
Background helpers for timers, network requests, DOM events, and more.
Microtask Queue
High-priority queue for Promise callbacks and await continuations.
Macrotask Queue
Queue for timers, user events, and other callbacks.
Event Loop
The checker that moves queued work to the stack when the stack is empty.
Use this diagram as the simple mental picture: the Event Loop waits for the Call Stack to become empty, runs Microtasks first, then handles Macrotasks.
JavaScript Runtime
+----------------------+
| Call Stack |
+----------+-----------+
|
Is Stack Empty?
|
Yes
|
Event Loop
|
+----------+-----------+
| |
v v
Microtask Queue Macrotask Queue
(Promise, await) (setTimeout, Events)
| |
+----------+-----------+
|
v
Execute CallbackKeep this order in your head. First synchronous code runs. Then, when the stack is empty, Microtasks run before Macrotasks.
Run synchronous code on the Call Stack.
Send slow work like fetch, timers, and events to Browser APIs.
When async work is ready, place its callback in the right queue.
Wait until the Call Stack becomes empty.
Run all Microtasks first, such as Promise callbacks.
Run one Macrotask next, such as setTimeout or a click handler.
Repeat the cycle so the UI stays responsive.
The chef does not pause the entire restaurant for one slow order. JavaScript works the same way: slow work is handled outside the Call Stack, then returned through queues.
The chef does not wait 20 minutes for pizza. Staff handles slow work in the background, and the manager brings it back when the counter is free.
Fast work finishes first. Slow work waits outside the main counter, then returns when JavaScript is free.
These are the scenarios you see in product work: loading products, button clicks, timers, checkout APIs, and UI loading states.
console.log("Load Header");
fetch("/api/products").then(() => {
console.log("Products Loaded");
});
console.log("Load Footer");Output
The API request runs in the background. JavaScript continues rendering the page, then handles the products when the response is ready.
button.onclick = () => {
console.log("Button Clicked");
};
console.log("App Ready");Output
The click callback waits until the user clicks. The browser queues it, and the Event Loop runs it when the stack is empty.
console.log("Start");
setTimeout(() => {
console.log("Reminder");
}, 5000);
console.log("Continue Working");Output
setTimeout is like setting a reminder. JavaScript does not stop working while the timer waits.
console.log("Validate Payment");
fetch("/create-order").then(() => {
console.log("Order Created");
console.log("Redirect to Thank You Page");
});
console.log("Show Loading Spinner");Output
The spinner appears immediately while the order API runs in the background. The UI does not freeze.
JavaScript is single-threaded and executes synchronous code using the Call Stack. When it sees asynchronous operations like fetch, setTimeout, or user events, the browser handles those operations in the background. Once the Call Stack becomes empty, the Event Loop first processes all pending Microtasks, such as Promise callbacks, and then processes Macrotasks, such as setTimeout callbacks. This keeps applications responsive without blocking the main thread.
Visual representation of how the Event Loop orchestrates asynchronous code execution.
Idle
Checks Call Stack → Microtasks → Rendering → Macrotasks
Empty
Empty
• Call Stack: Executes synchronous code. Only one function at a time.
• Web APIs: Handles asynchronous operations like setTimeout, fetch, and events.
• Microtask Queue: Higher priority. Contains Promise callbacks and queueMicrotask.
• Callback Queue: Lower priority. Contains setTimeout, setInterval callbacks.
• Event Loop: Continuously checks if Call Stack is empty, then processes queues in order.
Master these fundamental questions about the Event Loop that appear in technical interviews.
Single-threaded
One call stack at a time
Non-blocking
Async operations via APIs
Queue priority
Microtasks before Macrotasks
Collaborative
Browser controls rendering