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 immediately: it puts the callback into the timer queue, and it runs only after all the current synchronous code has finished and the call stack is empty.** Zero does not mean "now", it means "as soon as possible after everything else", and the browser is free to add a minimum delay of its own. ```javascript setTimeout(() => console.log('timeout'), 0); console.log('main'); // output: main, then timeout ``` **Key point:** a zero delay simply defers the call to the next turn of the event loop, which is handy to avoid blocking the interface and to let the browser repaint the DOM.Shown above the full answer for quick recall.Answer (EN)Image**`setTimeout(fn, 0)` does not run the function immediately, as it may look: it queues the callback `fn` to run after the current code, that is asynchronously, on the next turn of the event loop.** A zero delay does not mean "run now", it means "run as soon as possible, but after all the synchronous code". ## Theory ### TL;DR - `setTimeout(fn, 0)` schedules a call, it does not perform it. - The callback runs once the call stack is free, that is after all the current synchronous code. - The real delay is greater than zero: the specification lets the browser clamp nested timers to about 4 ms. - The reason is that JavaScript is single threaded: asynchronous callbacks wait in a queue. - It is used to defer code, to avoid blocking the UI, and to let the browser repaint the DOM. ### Quick example ```javascript setTimeout(() => console.log('timeout'), 0); console.log('main'); ``` Output: ```text main timeout ``` Even though the delay is zero, JavaScript first runs the whole current stack, everything synchronous, and only then takes callbacks from the timer queue (the callback queue). ### Why it works that way JavaScript is single threaded: it has one call stack and one task queue. Every asynchronous operation (`setTimeout`, `fetch`, `Promise`) goes into the event queue and runs only once the call stack has been freed. The event loop keeps checking: when the stack is empty, it takes the next task from the queue and pushes it onto the stack. ```javascript console.log('A'); setTimeout(() => console.log('B'), 0); console.log('C'); ``` Output: ```text A C B ``` ### Zero is not really zero The delay in `setTimeout` is a minimum waiting time, not a guaranteed one. The callback cannot start while the stack is busy, so a heavy synchronous operation easily pushes it back by hundreds of milliseconds. ```javascript setTimeout(() => console.log('timeout'), 0); const end = Date.now() + 500; while (Date.now() < end) { // busy loop blocks the stack for half a second } console.log('main'); // main first, timeout only after the loop is over ``` On top of that, browsers clamp nested timers: from roughly the fifth level of nesting the minimum delay becomes about 4 ms. In a background tab the interval can be larger still. ### What setTimeout(fn, 0) is used for - Waiting for the current operations to finish before reading the result. - Keeping the interface responsive: splitting a heavy computation into chunks so the browser can paint a frame in between. - Running code "after everything else", for example after all handlers of an event have fired. - Letting the browser update the DOM before the next step. ```javascript button.addEventListener('click', () => { status.textContent = 'Loading...'; // the browser can paint this first setTimeout(() => { runHeavyCalculation(); // deferred, so the text is visible }, 0); }); ``` For animation `requestAnimationFrame` is the better fit, and to defer until the next microtask use `queueMicrotask` or `Promise.resolve().then(fn)`. ### Summary table | What it does | Queues the callback for the next turn of the event loop | | --- | --- | | Delay | At least 0 ms, in practice a little later | | Execution | After all synchronous code | | Used for | Deferred code, sequencing, avoiding UI blocking | ### Common mistakes - Assuming that `setTimeout(fn, 0)` runs the function immediately and the result is available on the next line. - Writing `setTimeout(fn(), 0)`: the parentheses run the function right away and hand the timer `undefined`. - Counting on an exact delay: `0` is a minimum, the real time depends on how busy the stack is and on the browser. - Confusing it with microtasks: `Promise.resolve().then(fn)` runs before `setTimeout(fn, 0)`. - Using `setTimeout(fn, 0)` for animation instead of `requestAnimationFrame` and getting janky motion. - Not keeping the timer id when the call may need to be cancelled with `clearTimeout`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.