CodePark/ questions / Event loop
START PRACTICINGPRACTICE
Frontend question · JavaScript › Event loop

What is the practical difference between scheduling work with setTimeout(fn, 0) and queueMicrotask(fn) (or Promise.resolve().then(fn))?

setTimeout(fn, 0) runs fn later as a new task, after rendering may happen. queueMicrotask(fn) runs fn right after the current code, before any other task or rendering.

setTimeout(fn, 0):

  • It schedules a new macrotask (task).
  • It runs after the current task finishes and after all microtasks are done.
  • In browsers, the page usually gets a chance to render first.
  • The delay is a minimum, not a promise. When timers are nested inside each other more than about 5 levels deep, browsers clamp (raise) the delay to at least about 4 ms.

queueMicrotask(fn):

  • It runs fn as soon as the current call stack is empty.
  • It runs before any other task and before rendering.
  • It is useful to run something right after the current synchronous work, in order. An example is batching several state updates into one.

The danger: microtasks added by microtasks keep the loop busy. A recursive chain of microtasks never gives control back. The page cannot render or handle input.

To split heavy work so the UI stays responsive, give control back with a macrotask, not a microtask. Options are setTimeout, MessageChannel, or scheduler.postTask where the browser supports it.

  • A timer callback is a macrotask. It runs after all microtasks and possibly after a render.
  • A microtask runs right after the current call stack, before rendering.
  • The setTimeout delay is a minimum. After about 5 levels of nesting, timers are clamped to about 4 ms.
  • Recursive microtasks can block rendering and input forever.
  • For long work, give control back to the browser with macrotasks.