← Назад к вопросам
Ест ли setTimeout в Node.js
2.0 Middle🔥 181 комментариев
#JavaScript Core#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
setTimeout в Node.js - есть ли, как работает
Короткий ответ: ДА, setTimeout существует в Node.js. Это часть глобального API, которую Node.js поддерживает для совместимости с браузером и для удобства разработчиков.
История и контекст
setTimeout изначально - браузер API:
// В браузере (ванильный JavaScript)
setTimeout(() => {
console.log('Привет через 1 секунду');
}, 1000);
Node.js добавил поддержку для совместимости:
// В Node.js - точно так же работает!
setTimeout(() => {
console.log('Привет через 1 секунду');
}, 1000);
Как работает setTimeout в Node.js
Базовый пример:
// setTimeout в Node.js
console.log('Начало');
setTimeout(() => {
console.log('Через 1000мс');
}, 1000);
console.log('Конец');
// Вывод:
// Начало
// Конец
// Через 1000мс
Async операции:
// setTimeout не блокирует выполнение
console.time('timer');
setTimeout(() => {
console.log('Timeout 1000ms');
}, 1000);
// Это выполнится СРАЗУ же, не ждя timeout
fetch('https://api.example.com/data')
.then(res => res.json())
.then(data => {
console.log('Fetch завершен');
});
console.timeEnd('timer');
// Вывод:
// timer: 2ms
// Fetch завершен (если сеть быстрая)
// Timeout 1000ms
Различия между браузером и Node.js
1. Event Loop - одинаков:
// И в браузере, и в Node.js
console.log('1. Синхронный код');
setTimeout(() => {
console.log('3. setTimeout');
}, 0);
Promise.resolve()
.then(() => console.log('2. Promise'));
// Вывод везде одинаков:
// 1. Синхронный код
// 2. Promise (microtask queue)
// 3. setTimeout (macrotask queue)
2. Точность Timer'ов:
// В браузере:
setTimeout(() => {
console.log('Может быть ±1ms');
}, 1000);
// В Node.js:
setTimeout(() => {
console.log('Может быть ±10ms (зависит от OS)');
}, 1000);
// Причина: Node.js работает с системным timer'ом
// Точность зависит от ОС (Windows, Linux, macOS)
3. Глобальный scope:
// В браузере - window.setTimeout
window.setTimeout(() => {
console.log('Браузер');
}, 1000);
// В Node.js - global.setTimeout
global.setTimeout(() => {
console.log('Node.js');
}, 1000);
// Но можно вызывать просто setTimeout везде
setTimeout(() => {
console.log('Везде работает');
}, 1000);
setTimeout vs setImmediate (специфично для Node.js)
setImmediate - почти то же, но в другой фазе event loop:
// setImmediate выполняется раньше, чем setTimeout(fn, 0)
console.log('1. Старт');
setTimeout(() => {
console.log('3. setTimeout(fn, 0)');
}, 0);
setImmediate(() => {
console.log('2. setImmediate');
});
// Вывод в Node.js:
// 1. Старт
// 2. setImmediate
// 3. setTimeout(fn, 0)
// Почему? Event Loop phases:
// 1. Синхронный код
// 2. Microtasks (Promise, etc)
// 3. Timers (setTimeout, setInterval)
// 4. I/O callbacks
// 5. Check (setImmediate) <- здесь!
// 6. Close callbacks
Когда использовать что:
// setImmediate - когда нужно отложить на следующую фазу event loop
setImmediate(() => {
console.log('После текущей фазы');
});
// setTimeout - когда нужна задержка по времени
setTimeout(() => {
console.log('Через N миллисекунд');
}, 1000);
// setInterval - когда нужно повторять
setInterval(() => {
console.log('Каждую секунду');
}, 1000);
Практические примеры в Node.js
1. Отложенное выполнение:
// Пример: отправить ответ, потом что-то сделать
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('OK');
// Логирование в отдельной фазе, не блокирует ответ
setImmediate(() => {
console.log(`Запрос обработан: ${req.url}`);
});
});
server.listen(3000);
2. Пейнование долгой операции:
// Проблема: долгая операция блокирует event loop
function processLargeList(items) {
// Это займёт 5 секунд, event loop заморозится!
for (let i = 0; i < items.length; i++) {
heavyComputation(items[i]);
}
}
// Решение: разбить на части с setTimeout
function processLargeListAsync(items, batchSize = 100) {
let index = 0;
function processBatch() {
const end = Math.min(index + batchSize, items.length);
for (let i = index; i < end; i++) {
heavyComputation(items[i]);
}
index = end;
if (index < items.length) {
// Отложить следующую партию
setImmediate(processBatch);
// или
// setTimeout(processBatch, 0);
}
}
processBatch();
}
// Использование
processLargeListAsync(millionItems);
// Event loop остаётся отзывчивым
3. Обработка ошибок:
// setTimeout может выбросить ошибку
setTimeout(() => {
throw new Error('Ошибка в timeout');
}, 1000);
// Это ПОЙМАЕТ ОШИБКУ
process.on('uncaughtException', (error) => {
console.error('Необработанная ошибка:', error);
process.exit(1);
});
// Лучше: обработать ошибку внутри
setTimeout(() => {
try {
somethingThatMayThrow();
} catch (error) {
console.error('Ошибка обработана:', error);
}
}, 1000);
4. Отмена timeout:
// Сохранить ID timeout
const timeoutId = setTimeout(() => {
console.log('Это никогда не выполнится');
}, 1000);
// Отменить его
clearTimeout(timeoutId);
// Аналогично для setInterval
const intervalId = setInterval(() => {
console.log('Каждую секунду');
}, 1000);
clearInterval(intervalId);
setTimeout в Express (веб-фреймворк Node.js)
Пример: отправить ответ, потом выполнить действие:
const express = require('express');
const app = express();
app.post('/api/send-email', (req, res) => {
// Отправить ответ клиенту СРАЗУ
res.json({ status: 'accepted' });
// Отправить email БЕЗ БЛОКИРОВАНИЯ ответа
setImmediate(() => {
sendEmail(req.body.email);
});
});
app.listen(3000);
Пример: задержанная операция:
app.get('/schedule', (req, res) => {
// Запланировать что-то на позже
setTimeout(() => {
console.log('Выполнено через 10 секунд');
// Например, очистить кэш
cache.clear();
}, 10000);
res.json({ scheduled: true });
});
Когда НЕ использовать setTimeout в Node.js
Плохо: для периодических задач:
// Плохо: setTimeout может выпасть из-за ошибок
function scheduler() {
setTimeout(() => {
doWork();
scheduler(); // Если есть ошибка, цепь сломается
}, 1000);
}
// Хорошо: использовать node-cron или node-schedule
const cron = require('node-cron');
cron.schedule('*/1 * * * *', () => {
doWork();
});
Плохо: для критичных задач:
// setTimeout МОЖЕТ не выполниться, если процесс упадёт
setTimeout(() => {
saveImportantData();
}, 5000);
// Хорошо: использовать очередь (Bull, Bullmq, RabbitMQ)
const queue = new Bull('tasks');
queue.add({ action: 'save' }, { delay: 5000 });
Минимум знаний о event loop в Node.js
// setTimeout работает благодаря event loop'у
// Фазы event loop:
// 1. Timers (setTimeout, setInterval)
// 2. Pending callbacks
// 3. Idle, prepare
// 4. Poll (I/O events)
// 5. Check (setImmediate)
// 6. Close callbacks
// setTimeout ждёт своей очереди в фазе "Timers"
setTimeout(() => {
// Выполнится когда наступит фаза Timers
console.log('I/O не заблокирует это');
}, 0);
// А I/O может занять эту очередь
fs.readFile('/large-file', () => {
// Это выполнится раньше setTimeout выше
// Потому что это в фазе Poll
});
Лучшие практики
- Используй setImmediate для отложения в Node.js - быстрее чем setTimeout(fn, 0)
- Не используй setTimeout для периодических задач - используй cron
- Не полагайся на setTimeout для критичных операций - используй очереди
- Помни про event loop - setTimeout не гарантирует точность
- Обрабатывай ошибки - используй try-catch в callbacks
- Отменяй timeout когда не нужен - избегай утечек памяти
- Проверь, нужна ли тебе Worker Threads - для тяжёлых вычислений