Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «setTimeout(fn, 0)». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`setTimeout(fn, 0)` не виконує функцію одразу: він ставить колбек у чергу таймерів, і той виконається лише після того, як завершиться весь поточний синхронний код і звільниться call stack.** Нуль означає не «зараз», а «якнайшвидше після всього іншого», причому браузер має право додати власну мінімальну затримку. ```javascript setTimeout(() => console.log('timeout'), 0); console.log('main'); // output: main, then timeout ``` **Ключове:** нульова затримка лише відкладає виклик на наступний цикл event loop, що зручно, щоб не блокувати інтерфейс і дати браузеру оновити DOM.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`setTimeout(fn, 0)` не виконує функцію негайно, як може здатися: він ставить колбек `fn` у чергу на виконання після поточного коду, тобто асинхронно, у наступному циклі event loop.** Нульова затримка це не «виконати зараз», а «виконати якнайшвидше, але після всього синхронного коду». ## Теорія ### TL;DR - `setTimeout(fn, 0)` планує виклик, а не виконує його. - Колбек виконається після того, як звільниться call stack, тобто після всього поточного синхронного коду. - Фактична затримка більша за нуль: специфікація дозволяє браузеру мінімум близько 4 мс для вкладених таймерів. - Причина в тому, що JavaScript однопотоковий: асинхронні колбеки чекають у черзі. - Використовують, щоб відкласти код, не блокувати UI і дати браузеру оновити DOM. ### Швидкий приклад ```javascript setTimeout(() => console.log('timeout'), 0); console.log('main'); ``` Вивід: ```text main timeout ``` Хоча затримка дорівнює нулю, JavaScript спочатку виконує весь поточний стек, тобто все синхронне, і лише потім бере колбеки з черги таймерів (callback queue). ### Чому так JavaScript однопотоковий: у нього один call stack і одна черга задач. Усі асинхронні операції (`setTimeout`, `fetch`, `Promise`) потрапляють у чергу подій і виконуються тільки після того, як стек викликів звільниться. Event loop постійно перевіряє: якщо стек порожній, він бере наступну задачу з черги і кладе її в стек. ```javascript console.log('A'); setTimeout(() => console.log('B'), 0); console.log('C'); ``` Вивід: ```text A C B ``` ### Нуль насправді не нуль Затримка в `setTimeout` це мінімальний час очікування, а не гарантований. Колбек не запуститься, доки стек зайнятий, тому важка синхронна операція легко відкладе його на сотні мілісекунд. ```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 ``` Додатково браузери обмежують вкладені таймери: починаючи приблизно з п'ятого рівня вкладеності мінімальна затримка стає близько 4 мс. У неактивній вкладці інтервал може бути ще більшим. ### Для чого використовують setTimeout(fn, 0) - Дочекатися завершення поточних операцій, перш ніж читати результат. - Не блокувати інтерфейс: розбити важке обчислення на частини, між якими браузер встигне відмалювати кадр. - Запустити код «після всього іншого», наприклад після того, як спрацюють усі обробники події. - Дати браузеру оновити DOM перед наступним кроком. ```javascript button.addEventListener('click', () => { status.textContent = 'Loading...'; // the browser can paint this first setTimeout(() => { runHeavyCalculation(); // deferred, so the text is visible }, 0); }); ``` Для роботи з анімацією краще підходить `requestAnimationFrame`, а для відкладання до наступної мікрозадачі, `queueMicrotask` або `Promise.resolve().then(fn)`. ### Підсумкова таблиця | Що робить | Ставить колбек у чергу на наступний цикл подій | | --- | --- | | Час затримки | Мінімум 0 мс, фактично трохи пізніше | | Виконання | Після всього синхронного коду | | Використовують для | Відкладеного коду, синхронізації, уникнення блокування UI | ### Типові помилки - Вважати, що `setTimeout(fn, 0)` виконає функцію негайно і результат буде доступний на наступному рядку. - Писати `setTimeout(fn(), 0)`: дужки виконують функцію одразу і передають таймеру `undefined`. - Розраховувати на точну затримку: `0` це мінімум, реальний час залежить від зайнятості стека і від браузера. - Плутати з мікрозадачами: `Promise.resolve().then(fn)` виконається раніше за `setTimeout(fn, 0)`. - Використовувати `setTimeout(fn, 0)` для анімації замість `requestAnimationFrame` і отримувати ривки. - Не зберігати ідентифікатор таймера, коли виклик треба мати змогу скасувати через `clearTimeout`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.