What is going on here
Most people learn "microtasks run before tasks" from the classic promise-vs-setTimeout example and quietly generalise it into "all microtasks run, then all tasks". This scene breaks that. The microtask queue is drained after every single task, not once at the end of the script.
So the loop's real rhythm is: run one task, drain the microtask queue completely, run one task, drain again. A microtask created inside task 1 runs before task 2 starts, even though task 2 was queued much earlier. That is why the output interleaves rather than grouping.
This matters in practice whenever a task schedules promise work. A click handler that resolves a promise gets its continuation before the next queued click. And it is the mechanism behind microtask starvation: if a microtask keeps queueing another microtask, the checkpoint never ends, and the next task โ every timer, every event, every repaint โ waits forever.
Common questions
Do all microtasks run before all macrotasks?
No. The microtask queue is drained after each individual task, so a microtask queued during one task runs before the next task, but microtasks queued later still wait for their own checkpoint. The pattern is task, drain, task, drain.
When exactly does the microtask checkpoint run?
Whenever the JavaScript execution stack empties after a task completes. In practice that is after the script, after each timer or event callback, and before the browser proceeds to rendering.
Can a microtask delay a setTimeout callback?
Yes. A queued timer callback cannot run until the current checkpoint finishes, and because a microtask can queue more microtasks, an unbounded chain can postpone timers indefinitely.
Every question on one page โยทRun your own code โ
Embed this figure in your own post โEmbed this figure
Drop this into any article or course page. It stays interactive โ readers can step through it without leaving your site.