Skip to main content

Гарантія виконання таймера

Коротк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;
  1. requestAnimationFrame() - запускає колбек перед кожним кадром (~60 разів на секунду), ідеально підходить для плавних анімацій.
  2. 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, компенсація дрейфу

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.