JavaScriptRuntime mental models · Part 1

The event loop finally clicked when I stopped calling it a loop

A practical mental model for tasks, microtasks, and why asynchronous JavaScript runs in the order it does.

The event loop is often explained as a small circle that continuously checks a queue. That picture is useful, but it hides the part that matters most: JavaScript runs jobs to completion, and the host decides when another job may begin.

Once I started thinking in terms of turns instead of a literal spinning loop, ordering became much easier to predict.

A turn, drawn plainly

The current JavaScript job finishes, then microtasks drain, and then the host selects the next task.

A tiny experiment

order.js
console.log('first');
queueMicrotask(() => console.log('microtask'));
setTimeout(() => console.log('task'), 0);
console.log('last');

The current script finishes first. Microtasks drain next. Only then can the timer task start a new turn.

The rule I keep nearby

That gives us a compact rule worth remembering:

  1. Finish the current job.
  2. Drain the microtask queue.
  3. Let the host choose the next task.

The rule is smaller than most diagrams, but it explains more of the behavior I encounter in real code.