Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Event Queue и Event Loop в Node.js
Event Queue (очередь событий) — это ключевой механизм, который позволяет Node.js обрабатывать множество асинхронных операций неблокирующим способом. Node.js использует однопоточное событийное архитектуру, которая работает благодаря Event Queue и Event Loop.
Как работает Event Loop
Event Loop постоянно проверяет очередь событий и выполняет их в порядке FIFO (First In, First Out). Цикл выглядит так:
// Упрощённая модель Event Loop
while (eventQueue.waitForTask()) {
const task = eventQueue.pop();
execute(task);
while (microtaskQueue.hasTasks()) {
execute(microtaskQueue.pop());
}
}
Фазы Event Loop
Event Loop в Node.js состоит из нескольких фаз:
┌───────────────────────────┐
│ timers │ - setTimeout, setInterval
├───────────────────────────┤
│ pending callbacks │ - отложенные операции ввода-вывода
├───────────────────────────┤
│ idle, prepare │ - внутренние операции
├───────────────────────────┤
│ poll (опрос) │ - новые события I/O
├───────────────────────────┤
│ check │ - setImmediate
├───────────────────────────┤
│ close callbacks │ - закрытие сокетов
└───────────────────────────┘
Практический пример фаз
console.log('Script start'); // 1. Синхронный код
setTimeout(() => {
console.log('setTimeout'); // 5. Фаза timers
}, 0);
Promise.resolve()
.then(() => {
console.log('Promise'); // 3. Микротаск (microtask queue)
});
setImmediate(() => {
console.log('setImmediate'); // 6. Фаза check
});
console.log('Script end'); // 2. Синхронный код
// Вывод:
// Script start
// Script end
// Promise
// setTimeout
// setImmediate
Макротаски vs Микротаски
Макротаски (Macrotasks) — выполняются по одному в каждой итерации Event Loop:
- setTimeout
- setInterval
- setImmediate
- I/O операции
- UI рендеринг (в браузере)
Микротаски (Microtasks) — выполняются полностью после каждого макротаска, перед переходом к следующему:
- Promise (.then, .catch, .finally)
- async/await
- queueMicrotask()
- MutationObserver (в браузере)
console.log('1');
setTimeout(() => {
console.log('2'); // Макротаск
Promise.resolve().then(() => console.log('3')); // Микротаск внутри макротаска
}, 0);
Promise.resolve()
.then(() => {
console.log('4'); // Микротаск
setTimeout(() => console.log('5'), 0); // Макротаск из микротаска
});
console.log('6');
// Вывод:
// 1
// 6
// 4
// 2
// 3
// 5
Практический пример с асинхронными операциями
const fs = require('fs');
console.log('START');
// Макротаск: I/O операция
fs.readFile('file.txt', () => {
console.log('File read (I/O)'); // Выполнится в фазе poll
setImmediate(() => {
console.log('setImmediate in I/O'); // Выполнится в фазе check
});
});
// Макротаск: таймер
setTimeout(() => {
console.log('setTimeout');
}, 0);
// Микротаск: Promise
Promise.resolve()
.then(() => {
console.log('Promise'); // Выполнится сразу после синхронного кода
});
console.log('END');
// Примерный вывод:
// START
// END
// Promise
// setTimeout
// File read (I/O)
// setImmediate in I/O
Как писать эффективный код
// Плохо — блокирует Event Loop
function slowCalculation() {
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += i; // Синхронный код заблокирует весь Event Loop
}
return sum;
}
// Хорошо — используй асинхронность
function slowCalculationAsync() {
return new Promise((resolve) => {
setImmediate(() => {
let sum = 0;
for (let i = 0; i < 1000000000; i++) {
sum += i;
}
resolve(sum);
});
});
}
// Или используй рабочие потоки для тяжёлых вычислений
const { Worker } = require('worker_threads');
const worker = new Worker('./heavy-compute.js');
Ключевые моменты
- Event Loop — это сердце Node.js, позволяющее обрабатывать множество операций
- Микротаски выполняются перед макротасками
- Не блокируй Event Loop синхронным кодом
- setImmediate выполняется раньше, чем setTimeout при setTimeout с задержкой 0
- Используй async/await для улучшения читаемости асинхронного кода
- Для тяжёлых вычислений используй Worker Threads или разбивай на части