What is the Event Loop in JavaScript?
Understand the JavaScript event loop, call stack, and microtask vs macrotask ordering with clear examples and interview-ready answers.
Expected Interview Answer
The event loop is the mechanism that lets single-threaded JavaScript handle asynchronous work by continuously moving completed callbacks from queues onto the call stack whenever the stack is empty.
JavaScript runs synchronous code on one call stack. Slow operations like timers, network requests, and I/O are handed to the host environment (browser or Node) which signals completion by placing callbacks into task queues. The event loop repeatedly checks whether the call stack is empty and, if so, drains the entire microtask queue (Promises, queueMicrotask) first, then takes one macrotask (setTimeout, I/O, events). This is why Promise callbacks run before setTimeout even when both are ready.
- Keeps the UI responsive despite a single thread
- Enables non-blocking I/O and concurrency
- Defines predictable ordering of async callbacks
- Prioritises microtasks for fast Promise resolution
- Prevents long operations from freezing the page
AI Mentor Explanation
Picture a single umpire who can rule on only one delivery at a time. When a review is sent upstairs to the third umpire, the on-field umpire does not freeze the match; play continues and the verdict is announced the moment there is a gap between balls. The event loop is that on-field umpire: one execution thread, with slow decisions delegated elsewhere and their results slotted in whenever the stack is momentarily free.
Step-by-Step Explanation
Step 1
Run synchronous code
All ordinary statements execute frame by frame on the single call stack until it empties.
Step 2
Offload async work
Timers, fetch, and I/O are handed to the host (browser/Node) Web APIs, freeing the stack immediately.
Step 3
Queue the callbacks
When an async operation finishes, its callback is placed in either the microtask queue (Promises) or the macrotask queue (timers, events).
Step 4
Wait for an empty stack
The event loop only acts when the call stack is completely clear of synchronous work.
Step 5
Drain microtasks first
It empties the entire microtask queue before touching macrotasks, which is why Promises resolve before setTimeout.
Step 6
Take one macrotask
It then runs a single macrotask, re-checks microtasks, and repeats the cycle indefinitely.
What Interviewer Expects
- Understanding that JavaScript is single-threaded
- Clear separation of call stack, Web APIs, and queues
- Microtask vs macrotask priority ordering
- Why setTimeout(fn, 0) is not truly immediate
- Awareness that blocking the stack freezes async work too
Common Mistakes
- Claiming JavaScript is multi-threaded because of async
- Thinking setTimeout(fn, 0) runs the callback instantly
- Confusing microtasks and macrotasks or their ordering
- Believing Promises run on a separate thread
- Assuming the event loop interrupts running synchronous code
Best Answer (HR Friendly)
“The event loop is how JavaScript stays responsive even though it does one thing at a time. Slow jobs like timers or network calls are handed off, and their results are picked up the moment JavaScript is free, so the page never freezes while waiting.”
Code Example
console.log('1: sync start')
setTimeout(() => {
console.log('4: macrotask (setTimeout)')
}, 0)
Promise.resolve().then(() => {
console.log('3: microtask (Promise)')
})
console.log('2: sync end')
// Output order:
// 1: sync start
// 2: sync end
// 3: microtask (Promise)
// 4: macrotask (setTimeout)Follow-up Questions
- What is the difference between a microtask and a macrotask?
- Why does Promise.then run before setTimeout(fn, 0)?
- How does the Node.js event loop differ from the browser's?
- What happens if a synchronous loop never lets the stack empty?
- Where does queueMicrotask fit in the ordering?
MCQ Practice
1. In which order do these run: a synchronous log, a Promise.then, and a setTimeout(fn, 0)?
Synchronous code runs first, then the microtask queue (Promise) is drained fully, and only then does a macrotask (setTimeout) run.
2. Why can a long synchronous loop freeze a web page?
The event loop only runs queued callbacks when the call stack is empty; a long synchronous loop keeps the stack busy, so nothing else can proceed.
3. Which queue does a resolved Promise callback go into?
Promise reactions and queueMicrotask callbacks go into the microtask queue, which is fully drained before the next macrotask.
Flash Cards
Is JavaScript multi-threaded? — No. It runs on a single thread with one call stack; concurrency comes from the host offloading async work and the event loop queuing callbacks.
Microtask vs macrotask priority? — The entire microtask queue (Promises, queueMicrotask) is drained before each single macrotask (setTimeout, I/O, events).
When does the event loop act? — Only when the call stack is empty of synchronous work.
Is setTimeout(fn, 0) immediate? — No — it queues a macrotask that runs after sync code and all pending microtasks, so it is 'as soon as possible', not instant.