← Назад к вопросам

Ест ли 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
});

Лучшие практики

  1. Используй setImmediate для отложения в Node.js - быстрее чем setTimeout(fn, 0)
  2. Не используй setTimeout для периодических задач - используй cron
  3. Не полагайся на setTimeout для критичных операций - используй очереди
  4. Помни про event loop - setTimeout не гарантирует точность
  5. Обрабатывай ошибки - используй try-catch в callbacks
  6. Отменяй timeout когда не нужен - избегай утечек памяти
  7. Проверь, нужна ли тебе Worker Threads - для тяжёлых вычислений
Ест ли setTimeout в Node.js | PrepBro