← Назад к вопросам
В чем разница между микрозадачами и макрозадачами в Node.js?
2.0 Middle🔥 111 комментариев
#Node.js и JavaScript
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между микрозадачами и макрозадачами в Node.js?
Это фундаментальный вопрос о том, как работает Event Loop в Node.js. Микротасики (microtasks) и макротасики (macrotasks) определяют порядок выполнения асинхронного кода и критически важны для понимания асинхронности.
Определение
Микротасики (Microtasks) — это задачи с высоким приоритетом, которые выполняются в конце текущей фазы Event Loop, перед тем как перейти к следующей фазе.
Макротасики (Macrotasks) — это задачи с низким приоритетом, которые выполняются в одной из фаз Event Loop.
Event Loop в Node.js
┌─────────────────────────────────┐
│ Event Loop Фазы │
├─────────────────────────────────┤
│ 1. timers (setTimeout, setInterval) │
│ ↓ (выполнить все microtasks) │
│ │
│ 2. pending callbacks │
│ ↓ (выполнить все microtasks) │
│ │
│ 3. idle, prepare │
│ │
│ 4. poll (I/O callbacks) │
│ ↓ (выполнить все microtasks) │
│ │
│ 5. check (setImmediate) │
│ ↓ (выполнить все microtasks) │
│ │
│ 6. close callbacks │
│ ↓ (выполнить все microtasks) │
└─────────────────────────────────┘
Микротасики
Источники микротасик:
Promise.then(),Promise.catch(),Promise.finally()async/await(которые преобразуются в Promises)MutationObserver(в браузере)queueMicrotask()process.nextTick()(специфично для Node.js, выполняется ЕЩЁ раньше)
console.log('1. Синхронный код');
setTimeout(() => {
console.log('5. setTimeout (макротаска)');
}, 0);
Promise.resolve()
.then(() => {
console.log('3. Promise.then (микротаска)');
});
process.nextTick(() => {
console.log('2. process.nextTick (ещё раньше микротаски)');
});
setImmediate(() => {
console.log('6. setImmediate (макротаска в фазе check)');
});
console.log('4. Ещё синхронный код');
// Вывод:
// 1. Синхронный код
// 4. Ещё синхронный код
// 2. process.nextTick
// 3. Promise.then
// 5. setTimeout
// 6. setImmediate
Макротасики
Источники макротасик:
setTimeout()иsetInterval()— фаза timerssetImmediate()— фаза check- I/O операции (file system, network) — фаза poll
requestAnimationFrame()(в браузере)
console.log('Начало');
setTimeout(() => {
console.log('Таймер 1');
}, 0);
setTimeout(() => {
console.log('Таймер 2');
}, 0);
setImmediate(() => {
console.log('Immediate 1');
});
setImmediate(() => {
console.log('Immediate 2');
});
console.log('Конец');
// Вывод:
// Начало
// Конец
// Таймер 1 (выполняются оба setTimeout как одна фаза)
// Таймер 2
// Immediate 1 (выполняются оба setImmediate как одна фаза)
// Immediate 2
Детальный пример с async/await
async function processData() {
console.log('1. В асинх функции');
await Promise.resolve();
console.log('3. После await (это микротаска)');
}
console.log('0. Старт');
processData();
setTimeout(() => {
console.log('4. setTimeout (макротаска)');
}, 0);
console.log('2. После вызова асинч функции');
// Вывод:
// 0. Старт
// 1. В асинх функции
// 2. После вызова асинч функции
// 3. После await (это микротаска)
// 4. setTimeout (макротаска)
Сравнительная таблица
| Характеристика | Микротасики | Макротасики |
|---|---|---|
| Примеры | Promise, async/await | setTimeout, setImmediate |
| Приоритет | Высокий | Низкий |
| Выполнение | Сразу после текущей фазы | В отдельной фазе |
| Порядок | ВСЕ микротасики перед следующей фазой | По одной в фазе |
| process.nextTick | Выполняется ещё раньше | Не применимо |
Практический пример: очередь запросов
class RequestQueue {
async processRequests(urls) {
const results = [];
// Все Promise.then выполнятся как микротасики
for (const url of urls) {
const response = await fetch(url);
results.push(response); // Микротаска
}
return results;
}
scheduleCleanup() {
// Очистка в следующей фазе (макротаска)
setImmediate(() => {
this.cleanup();
});
}
}
Проблема: микротасики могут заморозить Event Loop
// ОПАСНЫЙ КОД!
function infiniteMicrotasks() {
Promise.resolve()
.then(() => infiniteMicrotasks()); // Бесконечный цикл микротасик!
}
infiniteMicrotasks();
// setTimeout НИКОГДА не выполнится!
setTimeout(() => {
console.log('Это никогда не выведется');
}, 0);
Профилирование Event Loop
const perf = require('perf_hooks');
const obs = new perf.PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`${entry.name}: ${entry.duration}ms`);
});
});
obs.observe({entryTypes: ['measure', 'function']});
// Регистрируем выполнение функции
perf.measure('start', undefined);
// Микротаски
Promise.resolve().then(() => {
perf.measure('microtask', 'start');
});
// Макротаски
setTimeout(() => {
perf.measure('macrotask', 'start');
}, 0);
Ключевые выводы
- Порядок: process.nextTick → Promises → setTimeout → setImmediate
- Все микротасики выполняются перед переходом к следующей макротаске
- Бесконечные микротасики могут заблокировать Event Loop
process.nextTick()— специфично для Node.js, имеет приоритет выше микротасик- Понимание Event Loop критично для отладки асинхронных проблем
Практическое применение: если тебе нужна задача с высоким приоритетом — используй Promise/async-await, если низким — setTimeout/setImmediate.