Skip to main content

Event loop

The Event Loop in Node.js is a mechanism that allows Node.js to handle asynchronous operations without blocking the main thread of execution. It coordinates the execution of code, collection and processing of events, and execution of I/O tasks. The primary advantage of the Event Loop is its ability to efficiently manage many I/O operations, which typically take a lot of time.

Big O

Main Stages of the Event Loop​

  1. Timers:

    • Executes callbacks scheduled by setTimeout() and setInterval().
  2. Pending Callbacks:

    • Executes callbacks deferred to the next loop iteration, such as certain types of errors from network operations.
  3. Idle, Prepare:

    • Internal phases used by Node.js for internal operations before polling for I/O events.
  4. Poll:

    • The most important phase where new I/O events are processed, and the majority of I/O-related callbacks are executed.
    • If no timers are scheduled, the Event Loop may block here waiting for new I/O events.
  5. Check:

    • Executes callbacks scheduled by setImmediate().
  6. Close Callbacks:

    • Executes "close" events like socket.on('close', ...).

Queues and Execution Order​

  • Microtasks:

    • The microtasks queue is processed after each phase of the Event Loop. Examples include process.nextTick() and Promise callbacks.
    • Microtasks have a higher priority and will be executed before moving to the next phase of the Event Loop.
  • Processing Phases:

    • Node.js cycles through all the stages described above, starting with Timers. If there are tasks in the microtasks queue, they will be executed before starting the next Event Loop stage.
Big O
Big O

Execution Example​

setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
Promise.resolve().then(() => console.log("promise"));
process.nextTick(() => console.log("nextTick"));

// Output:
// nextTick
// promise
// timeout
// immediate

Explanation​

  • process.nextTick and Promise callbacks are microtasks, so they execute first.
  • setTimeout with a zero delay runs in the Timers phase.
  • setImmediate runs in the Check phase.

Russian​

Event Loop (событийный цикл) в Node.js — это механизм, который позволяет Node.js выполнять асинхронные операции, не блокируя основной поток исполнения. Он отвечает за координацию выполнения кода, сбора и обработки событий, и выполнения подзадач, таких как I/O операции. Основное преимущество Event Loop — это возможность эффективной работы с большим количеством I/O операций, которые обычно занимают много времени.

Основные стадии Event Loop:​

  1. Timers (Таймеры):

    • На этом этапе выполняются колбэки, запланированные функциями setTimeout() и setInterval().
  2. Pending Callbacks (Ожидающие колбэки):

    • Здесь обрабатываются колбэки от некоторых операций системы, такие как ошибки при сетевых операциях (например, TCP ошибки).
  3. Idle, Prepare (Простой, Подготовка):

    • Внутренние этапы, используемые самим Node.js для подготовки к следующим этапам.
  4. Poll (Опрос):

    • Важнейший этап, который обрабатывает новые события I/O, и где большинство операций блока I/O выполняются.
    • Если в этом этапе нет таймеров, Event Loop может блокироваться здесь для ожидания новых событий.
  5. Check (Проверка):

    • На этом этапе выполняются колбэки, зарегистрированные с помощью setImmediate().
  6. Close Callbacks (Закрытие колбэков):

    • Здесь выполняются закрывающие колбэки, например, socket.on('close', ...).

Очереди и порядок выполнения:​

  • Микротаски (Microtasks):

    • Очередь микротасков выполняется после выполнения каждого этапа Event Loop. Примеры: process.nextTick() и Promise колбэки.
    • Микротаски имеют приоритет над остальными задачами и выполняются до перехода к следующему этапу Event Loop.
  • Фазы обработки:

    • Node.js проходит через все вышеописанные стадии в циклическом порядке, начиная с Timers. Если есть задачи в микротасках, они будут выполнены перед началом следующей стадии Event Loop.

Пример выполнения:​

setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
Promise.resolve().then(() => console.log("promise"));
process.nextTick(() => console.log("nextTick"));

// Результат:
// nextTick
// promise
// timeout
// immediate