Siddhant DevalAuthor
Senior Full-Stack Engineer·Aug 24, 2026·9 min read
The JavaScript Event Loop: Macro → Micro → Render
Correct the widespread 'Sync → Micro → Macro' myth by reading the WHATWG HTML Standard directly. Understand macrotasks, the microtask checkpoint, and why the formal cycle order changes how you think about UI responsiveness.
Technical Series
Event Loop Mastery
Part 1 of 2
The JavaScript Event Loop: Macro → Micro → Render
JavaScript is single-threaded — a fact so often stated it has become background noise. What is less understood is the precise algorithm that governs how the engine decides which piece of code to run next. Most tutorials teach a simplified model that works for predicting
console.log output but breaks completely when reasoning about UI rendering, animation smoothness, and why a Promise chain can freeze the page.This article reads the WHATWG HTML specification directly, compares it against V8 documentation and canonical browser engineer commentary, and replaces the common misconception with the architectural truth.

Expand
1. The Misconception: "Sync → Micro → Macro"
Countless tutorials, bootcamp curricula, and blog posts teach the JavaScript execution order as a three-tier priority list:
- Synchronous code runs first.
- Microtasks (Promises) run second.
- Macrotasks (setTimeout, setInterval) run last.
Running this code appears to confirm it:
javascript
The output —
A D B C — looks like Sync ran first, then Microtask B, then Macrotask C. The model appears to predict the output correctly. The problem is that the model is architecturally wrong, and that wrongness has real consequences when reasoning about rendering and UI freezes.2. The WHATWG Specification: What Actually Happens
The WHATWG HTML Standard defines the Event Loop Processing Model as a repeating algorithm with exactly these steps in exactly this order:
- Run a Task: Dequeue the oldest task from the task queue and execute it to completion.
- Perform a Microtask Checkpoint: Immediately process every queued microtask. If a microtask schedules another microtask, continue processing until the microtask queue is completely empty.
- Update the Rendering: Check whether the display needs a new frame. If it is time (per the VSync schedule), run
requestAnimationFramecallbacks, then Style Calculation, Layout, Paint, and Composite.- Repeat from Step 1.
There is no Step 0 for "synchronous code." Synchronous code is simply the payload that executes inside Step 1.
2.1 What the Four Lines of Code Actually Triggered
Applying the spec's model to the earlier example:
The output
A D B C is correct — but the reason is not "sync first, then microtasks, then macrotasks." It is: the script evaluation was Macrotask #1; when it finished, the Microtask Checkpoint fired; then the next lap of the loop picked up Macrotask #2 (the setTimeout callback).Mental Model Check
There are only two kinds of tasks in the event loop: Macrotasks and Microtasks. "Synchronous code" is not a category — it is what runs inside a macrotask. The synchronous-looking top-level script is simply the engine automatically queuing an "evaluate this script" macrotask and running it.
3. Why the Distinction Matters for UI
The practical consequence of the Macro → Micro → Render ordering is visible in these two patterns:
3.1 Promise Chain vs. setTimeout Loop
javascript
The
Promise.resolve().then(loop) pattern recursively appends to the Microtask queue. Because the Microtask Checkpoint is not considered "done" until the queue reaches zero, the engine stays locked in Step 2 indefinitely, and Step 3 (Render) is never reached. The browser appears frozen despite JavaScript technically "finishing" after each doWork() call.3.2 MutationObserver Behaviour
MutationObserver callbacks are dispatched as microtasks, not macrotasks. This means:javascript
This is intentional: DOM mutations that need to react to other DOM mutations should do so before any external code (macrotasks) runs, and before the render phase, to avoid flickering.
4. The Spec's Exact Language
The WHATWG HTML Standard, §8.1.7.3 "Processing model", mandates:
"Perform a microtask checkpoint" immediately after a task finishes. The checkpoint algorithm states: process microtasks until the queue is empty; if a new microtask is added during this processing, process it too before returning.
V8's documentation (which powers Chrome and Node.js) echoes this:
"Microtasks implement deferred execution for async/await and promises, and execute at the end of each task."
Jake Archibald, former Chrome engineer and author of the canonical article "Tasks, microtasks, queues and schedules":
"The microtask queue is processed after callbacks as long as no other JavaScript is mid-execution, and at the end of each task."
All three sources confirm the same formal order: Macrotask → Microtask Checkpoint → Render.
5. A Two-Minute Senior-Level Explanation
When asked to explain the event loop in an interview, a senior engineer's answer should cover:
"JavaScript is single-threaded, but the browser is multi-threaded. The Event Loop bridges the two. It runs a repeating algorithm: first it dequeues exactly one macrotask — asetTimeoutcallback, a click handler, a network response — and runs it to completion. When the macrotask finishes, the engine hits the Microtask Checkpoint and exhaustively drains the microtask queue: every resolved Promise, everyMutationObserver. Only after that queue reaches zero does the browser check whether it needs to paint a frame — roughly every 16.67 ms (For a 60Hz screen refresh rate). If it does, it runsrequestAnimationFrame, style, layout, paint, and composite. Then the loop picks up the next macrotask.The critical insight: a recursivePromise.thenchain starves the render phase because the Microtask Checkpoint never empties. AsetTimeoutloop does not, because each iteration is a separate macrotask that gives the render phase a chance to run between them."
6. References
Research & Synthesis Note
This article was developed with AI-assisted deep search, specification cross-referencing, and technical research synthesis.
#JavaScript#Event Loop#Microtasks#Macrotasks#WHATWG#Concurrency#Performance