Crux Read real JS snippets and predict the exact execution order — sync code, microtasks, tasks, rAF, and the Node phase ordering.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min
Predicting the exact log order is the cleanest test of whether you truly hold the loop’s model. Read each snippet, trace which queue every callback lands in, and pick the output a careful engineer would predict.
Goal
Practise the trace you run mentally in every async bug: classify each callback as sync, microtask, task, or frame work, and order them by the loop’s fixed rules — including the Node-specific reordering.
Heads-up setTimeout and Promise.then defer their callbacks. Only A and D run synchronously; B and C run after the current task, with the microtask C before the task B.
Heads-up The microtask checkpoint drains before the loop ever pulls a setTimeout task. C (microtask) always runs before B (task), regardless of the 0 ms delay.
Heads-up Microtasks never interrupt synchronous code. C is queued at resolution but runs only at the checkpoint, after all sync code (A and D) completes.
Snippet 2 — async/await desugared
async function run() { console.log('1'); await null; // suspends; resume is queued as a microtask console.log('2');}console.log('3');run();console.log('4');Promise.resolve().then(() => console.log('5'));
Quiz
Completed
What is the output order?
Heads-up await never blocks the thread. It suspends run() and schedules the resume as a microtask; synchronous code after run() (printing 4) executes before '2'.
Heads-up Code up to the first await runs synchronously when run() is called, so '1' prints before '4'.
Heads-up The microtask queue is FIFO. The await resume ('2') was queued before the .then ('5'), so '2' drains first.
Assuming the browser renders a frame on this turn, what is the most reliable ordering?
Heads-up rAF runs in step 4 (the render step), which comes after the microtask checkpoint. The promise microtask drains before any rAF callback.
Heads-up A microtask always precedes a task. promise runs before timeout, and rAF runs at the frame boundary which typically precedes the next task too.
Heads-up Microtasks never run between synchronous statements. promise is queued at resolution and drains only after end, at the checkpoint.
Inside this I/O callback, what is the deterministic output order in Node?
Heads-up Inside an I/O callback the check phase (setImmediate) runs in the current iteration, before the next iteration's timers phase (setTimeout). So immediate precedes timeout here.
Heads-up It is the reverse: process.nextTick has its own queue that drains before the microtask queue, so nextTick prints before promise.
Heads-up Source order is irrelevant. nextTick and microtasks drain between phases first; then phase ordering (check before next-iteration timers) decides immediate vs timeout.
Recap
Every async ordering puzzle resolves with the same trace: all synchronous code first, then the microtask checkpoint drains to empty (await resumes and .then callbacks in FIFO order), then the render step runs rAF on a frame boundary, then the loop pulls the next task (setTimeout, MessageChannel). Node layers a phase machine on top: process.nextTick drains before microtasks between every phase, and inside an I/O callback setImmediate (check phase, this iteration) beats setTimeout(0) (timers phase, next iteration). Classify each callback by queue, then order by these fixed rules — never by source position.