Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Гарантія виконання таймера». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Ні, не можна гарантувати точний час виконання таймера** у JavaScript (`setTimeout`, `setInterval` тощо). **Ключове:** JavaScript однопотоковий, і виконання таймера залежить від стану Event Loop та завантаженості стека викликів.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Короткa відповідь **Ні, не можна гарантувати точний час виконання таймера** у JavaScript (`setTimeout`, `setInterval` і т. п.). Причина проста: **JavaScript однопотоковий**, і виконання таймера залежить від стану **Event Loop** та **завантаженості стека викликів**. ## Чому так відбувається Коли ти викликаєш: ```javascript setTimeout(fn, 1000); ``` JS **не обіцяє**, що `fn` виконається **через рівно 1000 мс**. Він лише **ставить завдання в чергу**, щоб **виконати її не раніше**, ніж через 1000 мс. Якщо в момент, коли таймер "спрацював", стек викликів зайнятий, колбек чекатиме своєї черги. ## Приклад ```javascript console.log('Старт'); setTimeout(() => console.log('Таймер 1s'), 1000); const start = Date.now(); while (Date.now() - start < 3000) {} // блокуємо потік 3 секунди console.log('Кінець'); ``` **Результат:** ```javascript Старт (3 секунди паузи) Кінець Таймер 1s ``` Хоча таймер був на 1 секунду, спрацював він лише **через 3 секунди**. Чому? Тому що рушій **не міг виконати його раніше** - стек був зайнятий циклом. ## Мінімальна затримка (throttling) Навіть `setTimeout(fn, 0)` не запускає код "одразу" - мінімальна затримка все одно є: - У браузерах: зазвичай **4 мс** (за стандартом HTML Living Standard), - У Node.js: може бути менше, але теж **не миттєво**. Крім того, якщо вкладка браузера неактивна, затримка може бути збільшена (до 1000 мс і більше) - браузери **економлять ресурси**. ## Приклад з setInterval `setInterval()` **теж не гарантує** точні інтервали. Якщо функція всередині виконується довше, ніж сам інтервал, виклики будуть "накопичуватись" і виконуватись із запізненням. ```javascript setInterval(() => { const start = Date.now(); while (Date.now() - start < 1500) {} // блокуємо 1.5 сек console.log('tick'); }, 1000); ``` Інтервал - 1 секунда, але функція займає 1.5 сек, тому "тіки" йдуть з реальною затримкою 1.5, 3.0, 4.5... сек. ## Чому не можна точно | Причина | Пояснення | |---|---| | **Однопотоковість JS** | Поки виконується код, інші завдання чекають | | **Event Loop** | Таймери лише потрапляють у чергу - не запускаються миттєво | | **Обмеження браузера** | Є мінімальна затримка, а у фоні - сповільнення | | **Навантаження CPU** | При високому навантаженні таймери виконуються пізніше | | **Планувальник ОС** | JS не керує системним часом, а лише "просить" запустити завдання пізніше | ## Що можна зробити Якщо тобі потрібна **максимальна точність** (наприклад, в анімації чи синхронізації), можна використовувати альтернативи: 1. `performance.now()` - вимірює точний час у мілісекундах (з мікросекундами): ```javascript const start = performance.now(); // ... const elapsed = performance.now() - start; ``` 2. `requestAnimationFrame()` - запускає колбек перед кожним кадром (~60 разів на секунду), ідеально підходить для плавних анімацій. 3. `setTimeout` **з компенсацією дрейфу** (корекція затримки): ```javascript const start = Date.now(); let count = 0; function tick() { count++; const expected = start + count * 1000; const drift = Date.now() - expected; console.log(`tick ${count}, drift: ${drift}ms`); setTimeout(tick, 1000 - drift); } tick(); ``` Такий підхід враховує "запізнення" і вирівнює інтервали. ## Підсумок | Питання | Відповідь | |---|---| | Чи можна гарантувати точний час таймера? | Ні | | Чому? | Однопотоковість JS, Event Loop, мінімальні затримки та навантаження | | Що реально відбувається? | Таймер додається в чергу завдань, виконується пізніше | | Чи є альтернатива для точності? | `requestAnimationFrame`, `performance.now`, компенсація дрейфу |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.