JavaScript runs on a single thread, so it can only do one thing at a time. Synchronous code runs top to bottom on the call stack. Anything asynchronous — a setTimeout callback, a Promise .then, a click handler — does not run inline; it is placed in a queue. The event loop is the simple rule that decides what runs next: whenever the call stack is empty, it takes the next waiting task and runs it, then repeats. This tool makes that loop visible one step at a time.
There are actually two queues, and their priority is the key to the whole puzzle. Promise callbacks (and queueMicrotask) go into the microtask queue; setTimeout, setInterval, and most events go into the macrotask queue. The rule: after each macrotask (and after the initial script), the loop drains the entire microtask queue before it runs the next macrotask. That is why a Promise .then always beats a setTimeout with the same delay — the microtask is emptied first. Watch the two queues in this tool and the ordering stops being a mystery.
Common questions and answers about this topic.
Because Promise callbacks are microtasks and setTimeout callbacks are macrotasks, and the event loop drains the entire microtask queue after every macrotask (and after the initial script) before it runs the next macrotask. So even a setTimeout with 0ms waits in the macrotask queue while every pending microtask runs first.
Promise reactions (.then, .catch, .finally), await continuations, queueMicrotask callbacks, and MutationObserver callbacks are microtasks. setTimeout, setInterval, requestAnimationFrame, I/O, and most DOM events are macrotasks. The distinction matters because the loop empties all microtasks between macrotasks, so microtasks can starve rendering or later timers if you schedule them endlessly.
No. A 0ms delay only means the callback is eligible to run as soon as possible, but it still goes to the macrotask queue and waits until the current synchronous code and all pending microtasks have finished. Browsers also clamp nested timeouts to a minimum (about 4ms after several levels), so 0ms is a lower bound, not an instant call.