On this page · sections
JavaScript Event Loop & Runtime
Can you derive output order from the loop algorithm — not from memorized examples?
JavaScript is single-threaded per realm. Async work is scheduled by the host. The event loop decides what runs next. Rendering and timers live in that same story.
These questions test:
- Call stack vs host APIs vs queues
- Microtasks vs tasks
- Where
requestAnimationFramefits - Engine vs host
- Why
setTimeout(0)is not “immediate”
Implementing Promises is a coding topic. This page is the runtime model.
Questions
The Loop
Runtime
Senior-Level Follow-ups
The Loop
1. Explain the Event Loop
Why This Matters
Every “what logs first?” question is this algorithm plus the queues involved.
Problem
How does asynchronous JavaScript run? Cover the stack, host, task queue, microtask queue, and rendering.
Example
console.log("start");
setTimeout(() => console.log("timeout"), 0);
Promise.resolve().then(() => console.log("promise"));
console.log("end");start
end
promise
timeoutKey Idea
Call stack → one function at a time
Host → timers, network, DOM (not the JS engine)
Task queue → setTimeout, events, I/O
Microtask queue → Promise then, queueMicrotask, MutationObserver1. Run the current task until the stack is empty
2. Drain the ENTIRE microtask queue
(including microtasks queued while draining)
3. Browser may render: rAF → style → layout → paint
4. Take the next task
5. RepeatInterview Answer
“JavaScript runs one task at a time. Host APIs schedule callbacks. After each task, the engine drains all microtasks before the next timer or event. Rendering is an opportunity between tasks, not inside a Promise then.”
2. Microtasks vs Tasks
Why This Matters
Nested then callbacks still run before a setTimeout(0) from the same turn.
Problem
Predict this output and explain why.
Example
setTimeout(() => console.log("T"), 0);
Promise.resolve()
.then(() => {
console.log("M1");
queueMicrotask(() => console.log("M2"));
})
.then(() => console.log("M3"));
console.log("S");S
M1
M2
M3
TM2 is queued while draining and still runs in the same microtask checkpoint.
Interview Answer
“Tasks are macrotasks: timers, I/O, UI events. Microtasks are Promise jobs. The checkpoint empties the microtask queue completely. A timeout scheduled at delay 0 still waits for that drain.”
Runtime
3. Engine vs Host
Why This Matters
fetch and setTimeout are not ECMAScript. They are host APIs that enqueue work back into the loop.
Problem
What does the JS engine own, and what does the browser or Node own?
Example
App JS
→ Host APIs (DOM, fetch, timers, fs)
→ Engine (parse, compile, execute)
→ OS threads / networkV8 mental model: parse → Ignition bytecode → TurboFan for hot functions. That explains why first-load cost and later steady-state cost differ.
Each iframe and Worker is a realm: its own global, its own intrinsics, its own loop.
Interview Answer
“The engine executes ECMAScript. The host embeds it and provides I/O. Promises are language jobs; timers are host tasks. I do not treat Node’s loop phases as identical to the browser, but Promise microtask draining is aligned.”
4. Rendering and requestAnimationFrame
Why This Matters
rAF is not a microtask. It runs before paint, after the current task and its microtasks.
Problem
Where does requestAnimationFrame sit relative to Promises and timeouts?
Example
task
→ microtasks
→ rAF callbacks
→ style / layout / paint
→ next taskUse rAF to apply visual updates in the same frame. Do not use it as a generic defer — queueMicrotask and setTimeout have different contracts.
Reading layout (offsetHeight) after writes forces layout thrashing. Batch reads, then writes.
Interview Answer
“
requestAnimationFrameis scheduled for the next rendering opportunity. It runs after microtasks from the current turn and before paint. I use it for visual work, not as a substitute for Promises.”
Senior-Level Follow-ups
5. Why setTimeout(0) Is Late
The delay is a minimum. The callback waits for:
- The current task to finish
- All microtasks
- Other pending tasks
- Nested timeout clamping (4ms after a threshold of nested timers)
- Background-tab throttling
setTimeout(0) means “yield to the event loop,” not “run next.”
6. Node vs Browser Loops
Node uses libuv phases (timers, poll, check, …). setImmediate vs setTimeout ordering in Node is phase-specific and not a browser concept.
Shared rule: Promise reactions are microtasks and still drain between tasks.
Do not export a Node-only ordering trick as a browser interview answer.
7. Long Tasks and Responsiveness
A 200ms synchronous function is one task. No input, no paint, no other JS until it returns.
Break work with:
await/ chunked loopsscheduler.yield()where available- Workers for CPU (see Rendering, Performance & Workers)
INP and TBT are measurements of this blocking.
Final Interview Strategy
1. Draw stack, host, task queue, microtask queue
2. Drain microtasks after every task
3. Promise then is a microtask; setTimeout is a task
4. Engine ≠ host APIs
5. rAF is a render callback, not a Promise
6. setTimeout(0) is a yield, not immediate
7. Long tasks block the whole loopSenior-level signal: Derive the log order from the algorithm. Then connect the same model to rendering, throttling, and UI responsiveness.