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

Что такое Event Loop в Node.js и как он работает?

2.0 Middle🔥 201 комментариев
#Node.js и JavaScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Event Loop в Node.js: Сердце асинхронного выполнения

Event Loop — это фундаментальный механизм Node.js, который позволяет выполнять асинхронные операции в однопоточной среде. Это то, что делает Node.js идеальным для I/O-bound операций, несмотря на наличие только одного JavaScript потока.

Архитектура Event Loop

Event Loop работает на базе libuv (C-библиотека) и имеет четкую структуру обхода различных очередей.

Фазы Event Loop

1. Timers фаза

Выполняют callback-и от setTimeout() и setInterval(), чьи таймеры истекли:

setTimeout(() => {
  console.log('Timers phase');
}, 0);

console.log('Main script');

2. Pending callbacks фаза

Отложенные I/O callbacks из предыдущей итерации Event Loop.

3. Poll фаза (САМАЯ ВАЖНАЯ)

Это самая долгая и интересная фаза. Здесь обрабатываются все I/O операции: файлы, сеть, БД.

4. Check фаза

Выполняет callback-и от setImmediate():

setImmediate(() => {
  console.log('Check phase: setImmediate');
});

setTimeout(() => {
  console.log('Timers phase');
}, 0);

5. Close callbacks

Закрытие соединений (socket.destroy(), fs.close()).

Microtasks Queue

Критически важно: Microtasks выполняются между фазами Event Loop, не являясь частью самого Event Loop:

console.log('1. Main code');

setTimeout(() => {
  console.log('6. setTimeout');
}, 0);

Promise.resolve()
  .then(() => {
    console.log('2. Promise (microtask)');
  });

process.nextTick(() => {
  console.log('3. process.nextTick (microtask)');
});

setImmediate(() => {
  console.log('5. setImmediate');
});

console.log('4. Main code (synchronous)');

Порядок microtasks:

  1. process.nextTick() — самый высокий приоритет
  2. Rejected Promises
  3. Promise.then() / .catch() / .finally()
  4. MutationObserver

Блокировка Event Loop (CPU-bound операции)

Одна из главных ошибок — выполнение долгих синхронных операций:

function expensiveCalculation() {
  const start = Date.now();
  while (Date.now() - start < 5000) {
    // Цикл блокирует Event Loop
  }
  return 'done';
}

setTimeout(() => {
  console.log('Этот код выполнится только через 5+ секунд!');
}, 0);

Решение: используйте Worker Threads для CPU-bound операций:

const { Worker } = require('worker_threads');

const worker = new Worker('./heavy-calculation.js');
worker.on('message', (result) => {
  console.log('Результат:', result);
});

Практический пример

const fs = require('fs').promises;

async function demonstrateEventLoop() {
  console.log('1. Start');

  const filePromise = fs.readFile('file.txt', 'utf8');
  
  setImmediate(() => console.log('3. setImmediate'));
  
  setTimeout(() => {
    console.log('4. setTimeout 0ms');
  }, 0);

  process.nextTick(() => console.log('2. process.nextTick'));

  try {
    const data = await filePromise;
    console.log('5. File read completed');
  } catch (err) {
    console.error(err);
  }
}

demonstrateEventLoop();

Инструменты для отладки

  • clinic.js — анализ производительности
  • Node.js --inspect — встроенный дебаггер
  • 0x — профилирование Event Loop
  • autocannon — нагрузочное тестирование

Важные моменты

Порядок выполнения в Event Loop:

  1. Выполняется синхронный код
  2. Выполняются микротаски (process.nextTick, Promises)
  3. Выполняется первая фаза Event Loop (timers)
  4. Выполняются микротаски снова
  5. Выполняется следующая фаза (pending callbacks)
  6. И так далее...

Ключевые различия:

МетодТипПриоритетИспользование
process.nextTick()МикротаскСамый высокийОшибки, очистка
Promise.then()МикротаскВысокийАсинхронный код
setTimeout(,0)TimersСреднийОтложенное выполнение
setImmediate()CheckНизкийПосле I/O операций

Ключевые выводы

  • Event Loop обходит очереди асинхронных операций в фиксированном порядке
  • Microtasks имеют приоритет и выполняются между фазами
  • Poll фаза — самая важная, где обрабатываются I/O операции
  • Избегайте блокировки Event Loop синхронным кодом
  • Для CPU-bound операций используйте Worker Threads
  • Понимание Event Loop критично для оптимизации производительности приложений