The microtask queue empties before the loop takes a task
The common read: Whichever call gets queued first also runs first, so the timer callback (queued at line 2, before the promise callback at line 3) has to log before it.
Two lanes hold work while the running code finishes, and they don't wait their turn the same way. Carried over from run-to-completion: ready work parks in the task queue, and the loop takes one task per turn. A promise callback doesn't go there. It parks in a second lane, the microtask queue, and that lane plays by a different rule.
Every time the call stack empties, meaning the currently running code has finished, and before the loop is allowed to take its next task, it runs a microtask checkpoint: it drains the microtask queue completely. Not one microtask. All of them, in the order they were queued. Only once that queue is empty does the loop reach into the task queue and take its one item for the turn.
That's why C beat B above. Both were parked while the script ran. The script finishes, the stack empties, the checkpoint fires, and C is the only thing in the microtask queue, so it runs immediately. B is still sitting in the task queue when that happens, and it waits for its own turn after the checkpoint clears.
