What does this script print, and why? console.log('start'); setTimeout(() => console.log('timeout'), 0); Promise.resolve().then(() => console.log('promise')); console.log('end');
answer
- the script itself finishes first
- two queues, not one
- one drains fully, the other one at a time
- the timer callback is last
basics
~20 sIt prints start, end, promise, timeout. All the top-level synchronous code runs first, then the promise callback runs as a microtask once the script finishes, and the setTimeout callback runs last as a separate task.
solid answer
~40 sThe output is `start`, `end`, `promise`, `timeout`. The script itself runs to completion first, so `start` and `end` print in source order. `setTimeout` only hands the callback to the host timer service and returns immediately; it never runs the callback inline. `Promise.resolve()` produces an already-fulfilled promise, so `.then` enqueues its callback as a microtask right away — but microtasks only run once the call stack is empty. When the script ends, the engine drains the microtask queue, printing `promise`, and only then picks up the next task from the task queue, printing `timeout`. Changing the delay from 0 to any value does not reorder those last two: microtasks always drain before the next task runs.
go deeper
Be able to state the output and the one-sentence reason: synchronous code first, then promise callbacks, then timer callbacks. Say plainly that setTimeout never runs its callback inline, no matter how small the delay.
Explain the mechanics: an already-fulfilled promise enqueues its reaction as a microtask immediately, the queue is drained completely once the stack empties, and only one task is taken per turn of the loop. Trace a chained variant without hesitating.
Show how you trace unfamiliar code methodically rather than pattern-matching — walk the source into now/microtask/task columns and justify each step. Be ready to say which parts of the order are language guarantees and which are host-dependent timing.
Own the consequence for design: code whose correctness depends on this ordering is fragile documentation-free coupling. Talk about when to make sequencing explicit with awaited promises instead of relying on a reader reconstructing queue order.
## The output ``` start end promise timeout ``` This is the canonical "what logs first" puzzle, and every part of the answer follows from one model you can draw on a whiteboard. ## Three places code can be waiting At any instant, JavaScript code lives in one of three places: - **The call stack** — what is executing right now. There is exactly one, and only one thing runs at a time. - **The microtask queue** — promise reaction callbacks (the functions you pass to `.then`, `.catch`, `.finally`) and callbacks passed to `queueMicrotask`. - **The task queue** — callbacks the host hands back later: timer callbacks from `setTimeout`/`setInterval`, I/O completions, dispatched events. The rule that decides this puzzle: nothing from either queue can run while the stack is non-empty, and when the stack empties, the microtask queue is emptied completely before the next task is taken. ## Line by line 1. `console.log('start')` is ordinary synchronous code. It prints immediately. 2. `setTimeout(fn, 0)` calls into the host, registers `fn` with the timer service, and **returns immediately**. Nothing of `fn` runs here. After the delay elapses, the host puts `fn` into the task queue — being *in the queue* is not the same as *running*. 3. `Promise.resolve()` creates a promise that is already fulfilled. Calling `.then(cb)` on it registers `cb` as a reaction; because the promise is already settled, a promise job carrying `cb` is enqueued on the microtask queue right there. Again: enqueued, not executed — the stack still has the running script on it. 4. `console.log('end')` prints. At this point the script's last statement has finished, so the stack empties. ## What happens after the script The engine performs a microtask checkpoint: it takes microtasks one at a time until the queue is empty, so `cb` runs and prints `promise`. Only then does the loop pick up one task — the timer callback — which prints `timeout`. Note the asymmetry that trips people up: the whole microtask queue is drained, whereas tasks are taken one per turn. If you had queued three promise callbacks and three timers, all three promise callbacks would print before the first timer callback. ## Why the 0 does not help Two independent reasons, and it is worth giving both: - A delay of `0` is a *minimum*, not a promise of immediacy — the callback becomes eligible after at least that much time. - Even if it were eligible instantly, it still sits in the task queue, and the microtask checkpoint happens before the loop takes another task. So no delay value can make `timeout` print before `promise` here. ## A variant worth being ready for Chaining does not change the relationship to timers: ```js Promise.resolve() .then(() => console.log('p1')) .then(() => console.log('p2')); setTimeout(() => console.log('t'), 0); ``` This prints `p1`, `p2`, `t`. The second `.then` callback is queued *while the first microtask is running*, and microtasks queued during the drain are part of the same drain — so both print before the timer. ## How to answer this at a whiteboard Draw three columns — *now* (synchronous), *microtasks*, *tasks* — and walk the source top to bottom, writing each callback into the column it lands in rather than trying to hold the order in your head. Then read the answer off the columns: everything in *now* in source order, then everything in *microtasks*, then *tasks* one at a time. Saying the model out loud as you trace is what an interviewer is actually grading; the four-line output alone, guessed correctly, proves much less.
- If you change the delay from 0 to 100, does the printed order change?No — the output is still `start`, `end`, `promise`, `timeout`. The delay only affects when the timer callback becomes eligible to be queued; it was already going to run after the microtask drain. A larger delay pushes `timeout` later in wall-clock time, not earlier in the order.
- What if a second `.then` is registered on that same already-fulfilled promise, after the first one?Both callbacks are queued as microtasks, in registration order, and both run before the timer callback. Within one queue the order is first-in-first-out, so the earlier-registered reaction prints first — the interesting boundary is between the queues, not inside one.
- Where would a callback passed to `queueMicrotask` print in this script?In the microtask drain, in FIFO order with the promise reactions — so before `timeout`. `queueMicrotask` and a `.then` on an already-settled promise put work in the same queue; the promise version just carries a value and rejection handling along with it.
saying these in an interview costs you the question
- Says setTimeout with 0 delay runs right after that line
- Claims timers and promise callbacks share one queue
- Thinks .then runs its callback synchronously when already resolved
- Says 'end' prints after 'promise' because promises are faster
- Explains the order by 'promises have higher priority' with no mechanism