The concept
One thread runs one task at a time: microtasks go before the next task, and a frame only fits between two.
The JavaScript event loop is how a browser runs a page's code on a single thread: it takes one task from its task queues, runs it to the end on the call stack, empties the microtask queue, and renders a frame when one is due, then starts again.
A task is a unit of work the browser schedules: running a script, dispatching a click, calling back a timer. Browsers keep several task queues and choose which one to serve next, but they run one task at a time, and nothing interrupts the code it starts until the call stack is empty.
A microtask is a job the running code queues to run right after it: a promise's then callback, the rest of an async function after await, queueMicrotask. Once the stack is empty, at the end of every task and after each callback the browser calls, the event loop runs every queued microtask, those queued along the way included, before anything else.
Rendering waits its turn too. When a frame is due, roughly every 16.7 ms on a 60 Hz screen, the browser runs the animation-frame callbacks, recalculates style and layout, then paints. A task that holds the stack for 200 ms leaves no room for any of it: the page cannot update or run a click's handler until the task is over.
Timers count in parallel, off the main thread. setTimeout(cb, 0) only asks for cb to be queued as a task once at least 0 ms have passed; then it waits for the event loop to pick it. That is why the script in this machine logs A, D, C, then B.