setTimeout(cb, 0): Why It Does Not Run Immediately in JavaScript
setTimeout with 0 delay is a common pattern but it does not run immediately. Here is why and what it is useful for.
setTimeout(cb, 0): Why It Does Not Run Immediately
setTimeout(callback, 0) is a common pattern, but it does not run the callback immediately. Here is why and what it is actually useful for.
What Happens
setTimeout(() => console.log("later"), 0); console.log("now");
Output: now, later.
- The callback goes to the macrotask queue.
- Synchronous code continues (
"now"logs). - After the stack is empty and microtasks are done, the event loop moves the callback to the stack.
"later"logs.
Why It Does Not Run Immediately
setTimeout always goes through the Web API and the macrotask queue. The event loop only runs macrotasks when the call stack is empty. Even with 0 delay, the callback waits for synchronous code to finish.
Microtasks Run First
setTimeout(() => console.log("timeout"), 0); Promise.resolve().then(() => console.log("promise"));
Output: promise, timeout. The promise callback (microtask) runs before the timer callback (macrotask).
What setTimeout(cb, 0) Is Useful For
- Deferring work: let the browser render before a heavy task.
- Breaking long tasks: process in chunks, yielding between them.
- Allowing the browser to paint: show a loading state before blocking.
Better Alternatives
queueMicrotask(fn): runs as a microtask (before the next macrotask).requestAnimationFrame(fn): runs before the next paint (for visual updates).requestIdleCallback(fn): runs when the browser is idle.
The Takeaway
setTimeout(cb, 0) does not run immediately. It goes to the macrotask queue and runs after the stack is empty and microtasks are done. It is useful for deferring work and breaking long tasks. For better alternatives, use queueMicrotask, requestAnimationFrame, or requestIdleCallback.
No. The callback goes to the macrotask queue. The event loop runs it only after the call stack is empty and all microtasks are done. So it runs after the current synchronous code, not immediately.
Because promise callbacks go to the microtask queue, which the event loop drains completely before touching the macrotask queue where setTimeout callbacks live. Microtasks always run first.
Deferring work to keep the UI responsive, breaking long tasks into chunks (yielding between them), and allowing the browser to paint a UI update before a heavy task blocks the thread.
Yes. After 5 nested levels, browsers may throttle setTimeout to a minimum of 4ms. In background tabs, timers are often throttled to 1 second minimum. This prevents abuse.
queueMicrotask(fn) runs fn as a microtask (before the next macrotask). requestAnimationFrame(fn) runs fn before the next paint (best for visual updates). requestIdleCallback(fn) runs fn when the browser is idle.
Ready to master React completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master React
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

