Topics
v5.0.0
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 requestAnimationFrame fits
  • Engine vs host
  • Why setTimeout(0) is not “immediate”

Implementing Promises is a coding topic. This page is the runtime model.

Questions

The Loop

  1. Explain the Event Loop
  2. Microtasks vs Tasks

Runtime

  1. Engine vs Host
  2. Rendering and requestAnimationFrame

Senior-Level Follow-ups

  1. Why setTimeout(0) Is Late
  2. Node vs Browser Loops
  3. Long Tasks and Responsiveness

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 timeout

Key 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, MutationObserver
1. 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. Repeat

Interview 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 T

M2 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 / network

V8 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 task

Use 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

“requestAnimationFrame is 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:

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 loop

Senior-level signal: Derive the log order from the algorithm. Then connect the same model to rendering, throttling, and UI responsiveness.

Last updated on