Suggest an editImprove this articleRefine the answer for “setTimeout(fn, 0)”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`setTimeout(fn, 0)` does not run the function instantly: it only puts the callback `fn` into the macrotask queue so that it runs after the current code and all microtasks have finished.** A delay of `0` means "as soon as possible once the call stack is free", not "right now", because the Event Loop never interrupts the current stack. That makes such a call a way to defer work to the next Event Loop iteration: to let the browser repaint, to break up heavy synchronous code, or to reset the stack in recursion. ```javascript console.log('A'); setTimeout(() => console.log('B'), 0); console.log('C'); // A, C, B ``` **Key point:** a zero delay queues the callback as a macrotask, so it runs after the synchronous code and after every microtask.Shown above the full answer for quick recall.Answer (EN)Image**`setTimeout(fn, 0)` does not run the function instantly: it simply puts the callback `fn` into the macrotask queue so that it runs after the current code and all microtasks have finished.** A zero delay means "on the next Event Loop iteration", not "right now". ## Theory ### TL;DR - `setTimeout(fn, 0)` queues `fn` as a macrotask instead of running it immediately. - The callback waits for the call stack to become free, because the Event Loop never interrupts code that is already running. - Every microtask, such as `Promise.then` and `queueMicrotask`, runs before it. - The order is always: the call stack, then microtasks, then `setTimeout`. - It is the standard way to defer work, to break up a long synchronous block and to let the interface update. - The call returns a timer id, which you can cancel with `clearTimeout`. ### Quick example ```javascript console.log('A'); setTimeout(() => console.log('B'), 0); console.log('C'); ``` Output: ```text A C B ``` Why not `A`, then `B`, then `C`? Because a timer callback is not allowed to cut into code that is already running. ### What happens step by step 1. `console.log('A')` runs right away, on the call stack. 2. `setTimeout(() => console.log('B'), 0)` hands the task to the **Web API**, as a timer with a `0` ms delay. 3. The timer "fires" instantly and the callback is added to the **macrotask queue**. 4. JavaScript keeps running the current stack, so it prints `C`. 5. Once the call stack is empty, the **Event Loop** takes `() => console.log('B')` from the queue and runs it. ### Why even 0 does not run immediately Because everything in JavaScript goes through the **Event Loop**, and it **never interrupts** the current call stack. > Even with a delay of `0`, the callback still has to wait until the stack is free. So `setTimeout(fn, 0)` is a way to **defer a function** to the next Event Loop iteration. One more detail worth remembering: by specification browsers apply a minimum threshold of about 4 ms for nested timers, so the real delay is almost never zero. ### Example with a promise (microtask) ```javascript setTimeout(() => console.log('timeout'), 0); Promise.resolve().then(() => console.log('promise')); console.log('end'); ``` The order: ```text end promise timeout ``` Explanation: - `Promise.then()` creates a **microtask**; - `setTimeout()` creates a **macrotask**; - and **microtasks always run before** macrotasks. ### Practical uses 1. **Defer execution** so the main code is not blocked: ```javascript setTimeout(() => { console.log('Runs after the main code'); }, 0); ``` 2. **Break a synchronous loop** so the interface has time to update: ```javascript for (let i = 0; i < 1e9; i++) {} // heavy operation console.log('The interface is frozen...'); setTimeout(() => { console.log('Now we run after the pause'); }, 0); ``` 3. **Reset the stack**, for example in recursive computations: ```javascript function nextStep() { setTimeout(nextStep, 0); // every repetition is a new Event Loop iteration } nextStep(); ``` ### Summary | Property | Value | | --- | --- | | **What it does** | Queues the callback as a macrotask | | **When it runs** | After the current stack and all microtasks | | **A delay of "0"** | Not instantly, but on the next Event Loop cycle | | **Queue** | Macrotasks | | **Returns** | A timer id, cancellable with `clearTimeout` | Visually it looks like this: ```text [Call Stack] -> the current code runs here [Microtask Queue] -> promises and queueMicrotask [Task Queue] -> setTimeout(fn, 0) ``` `setTimeout(fn, 0)` always waits until: 1. the call stack is cleared, 2. the microtasks have run, 3. and only then does `fn` run. ### Common mistakes - **Reading `0` as "immediately".** It means "as soon as possible once the stack is free", and the difference matters a lot when heavy synchronous code is nearby. - **Treating `setTimeout(fn, 0)` and `Promise.resolve().then(fn)` as equivalent.** A promise is a microtask and will always beat the timer. - **Counting on exactly 0 ms.** Browsers clamp nested timers to roughly 4 ms, and in a background tab the delays grow much larger. - **Curing a frozen interface with a zero timer.** It only gives the browser a chance to repaint between chunks of work; if the work itself is heavy, split it into pieces or move it to a Web Worker. - **Forgetting `clearTimeout`.** A deferred callback can fire after the component has already left the screen and then touch stale data.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.