Ответ
В Node.js таймеры, установленные через setTimeout(), обрабатываются на фазе Timers цикла событий (Event Loop). Задержка выполнения колбэка возникает из-за того, что Event Loop — однопоточный, и фаза Timers наступает только после завершения текущего синхронного кода и других фаз (например, Pending callbacks, Poll).
Основные причины задержки:
- Блокировка основного потока долгими синхронными операциями.
- Выполнение других фаз Event Loop, которые заняли больше времени.
- Загрузка процессора другими задачами в системе.
Пример блокировки Event Loop:
console.log('Start');
setTimeout(() => console.log('Timeout callback'), 100);
// Долгая синхронная операция блокирует Event Loop
const start = Date.now();
while (Date.now() - start < 2000) { /* Ждём 2 секунды */ }
console.log('End after blocking loop');
// Вывод:
// Start
// End after blocking loop
// Timeout callback (выполнится через ~2000 мс, а не 100 мс)
Важно: setTimeout(fn, delay) гарантирует, что функция fn будет вызвана не раньше, чем через delay миллисекунд, но не гарантирует точное время. Для точного измерения времени лучше использовать performance.now() или Date.now() внутри колбэка.
Минимальная задержка: В Node.js есть минимальная задержка (~1 мс), но она может увеличиваться в зависимости от нагрузки.