The Browser Event Loop
Call stack, task, microtask checkpoint, rendering opportunity. The scheduling model that explains why a synchronous loop freezes the page and a promise chain does not yield a frame.
One call stack, task queues, a microtask checkpoint that drains to empty, and a rendering opportunity between tasks — the model that predicts any ordering puzzle.
Where tasks come from, why each one runs to completion, and why `setTimeout(fn, 0)` is neither zero nor a promise about when.
Drained to empty after every callback, including microtasks queued during the drain — which is exactly why an unbounded promise chain freezes a page with no long task to blame.
A frame can only be produced between tasks, after the microtask checkpoint — which is the mechanical reason a promise chain never lets the browser paint.
One task that runs long blocks input, rendering and accessibility-tree updates at the same time — which is why "the page froze" is one symptom with one cause.
Script, DOM, style, layout, event dispatch and the accessibility tree share one thread — and knowing what is not on it is what makes moving work possible.
Breaking work into pieces the loop can get between — with honest limits: zero is not zero, idle callbacks are not everywhere, and the newer scheduling APIs are not yet universal.