Event Loop Explained With Examples
Understand how the JavaScript event loop runs synchronous code, microtasks, and macrotasks with practical interview examples.
Direct definition
The JavaScript event loop decides what runs next after the current call stack is empty. It coordinates synchronous code, runtime APIs, microtasks such as promises, and macrotasks such as timers and events.
Small Runnable Code Example
console.log("Start");
setTimeout(() => {
console.log("Timeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");Expected output
Start End Promise Timeout
Synchronous logs run first. The promise callback is a microtask, so it runs before the timer macrotask.
Visual Event Loop Diagram
Flow diagram
Synchronous work enters the call stack. Runtime APIs schedule callbacks into queues. Microtasks run before the next macrotask.
flowchart LR
A[Call Stack] --> B[Web APIs / Runtime APIs]
B --> C[Microtask Queue]
B --> D[Macrotask Queue]
C --> E[Event Loop]
D --> E
E --> AHow JavaScript Executes This Code
console.log("Start") runs on the call stack.
setTimeout schedules its callback in the macrotask queue.
Promise.then schedules its callback in the microtask queue.
console.log("End") runs before queued callbacks.
The call stack becomes empty.
The microtask queue runs, printing "Promise".
The macrotask queue runs next, printing "Timeout".
Internal Components
Call stack
Runs synchronous JavaScript one frame at a time.
Web APIs / Runtime APIs
Handle timers, events, network work, and platform callbacks outside the stack.
Microtask queue
Holds Promise callbacks and runs before the next macrotask.
Macrotask queue
Holds timers, events, intervals, and other scheduled tasks.
Common Event Loop Problems
Blocking the main thread
Long synchronous loops prevent timers, rendering, and input handling from running. Break heavy work into chunks or move it to a worker.
Delayed setTimeout
setTimeout(fn, 0) means run after the current stack and microtasks, not immediately.
Microtask starvation
Repeatedly scheduling promises can delay macrotasks and make the page feel stuck.
Callback hell
Deep nested callbacks make execution order hard to reason about. Prefer promises or async/await for clearer sequencing.
Best Practices
- Keep synchronous work short.
- Use async/await for readable async flows.
- Understand that promises run before timers.
- Use workers for CPU-heavy browser tasks.
Quiz
What runs first after the synchronous call stack becomes empty?
Correct answer: microtasks run after the stack clears and before the next macrotask.