JavaScript finishes the current synchronous task, drains queued microtasks, and only then starts the next task. Promise reactions are microtasks; a setTimeout() callback is a task even when its delay is zero.
Last updated: October 13, 2026.
console.log('A: synchronous');
setTimeout(() => console.log('D: timeout task'), 0);
Promise.resolve()
.then(() => console.log('B: promise microtask'))
.then(() => console.log('C: chained microtask'));
// Output: A, B, C, DA zero-millisecond timeout means the callback becomes eligible after the delay; it does not interrupt the current task or jump ahead of microtasks already queued by resolved promises.
Follow one event-loop turn
MDN’s promise guide explains that .then() callbacks never run synchronously. When the stack becomes empty, the runtime processes the microtask queue. A chained .then() schedules another microtask, so it also finishes before the next timeout task begins.
The MDN microtask guide distinguishes tasks from microtasks and notes that the microtask queue is drained after a task. This ordering is why promise-based state updates are visible before a timer callback scheduled in the same synchronous turn.
Avoid timing assumptions in application code
Use await or return a promise when one operation depends on another. Do not use setTimeout(..., 0) as a general synchronization mechanism. Timers can be delayed by other work and browser throttling, while an endlessly replenished microtask queue can postpone rendering and later tasks.
queueMicrotask() can normalize a small callback that should run after the current stack but before the next task. Keep that work short. For visual updates that should align with browser rendering, use the rendering API that matches the job instead of substituting a promise or timer.
When debugging, label logs with the scheduling mechanism and reduce the example to synchronous code, one promise, and one timer. Add network requests or framework updates only after the basic ordering is clear. Continue with running code after DOM readiness, calling a server with Fetch, and tracing JavaScript errors.