What each knob does
Every example on this site is a fixed snippet. This page is the opposite: one program with four dials, so you can change a single variable and see exactly which part of the output moves. The code on the left is regenerated from your settings each time, and the figure re-runs it step by step.
Timer delay
The delay passed to setTimeout is a minimum, not a schedule. Whether you pick 0ms or 1000ms, the callback lands in the callback queue and still waits for the call stack to empty and for every pending microtask to finish. A longer delay only changes how long it sits in Web APIs first.
Promise chain depth
Each .then schedules the next one as a new microtask, and the event loop drains the whole microtask queue before it takes a single timer callback. Push the depth to 100 and the zero-delay timeout waits behind all hundred steps. That is the same mechanism behind microtask starvation.
Blocking loop
A synchronous loop holds the call stack. While it runs, nothing else can: no timers, no promise callbacks, no clicks, no rendering. Raising the iteration count does not reorder the output, it just delays everything queued behind it, which is exactly what a frozen page feels like.
Nested timeouts
A setTimeout scheduled from inside another timer callback goes to the back of the callback queue, so it runs on a later turn of the loop. Any microtasks queued in between still jump ahead of it.
Common questions
Why does setTimeout(fn, 0) run after a promise?
Promise callbacks are microtasks and timers are tasks. After the current script finishes, the event loop empties the microtask queue completely before it picks up the next task, so the promise always wins.
Can a long loop make a timer fire late?
Yes. The timer can expire on time, but its callback cannot run until the call stack is empty. A loop that takes 200ms delays a 10ms timer to at least 200ms.