Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое Макрозадача в JavaScript
Макрозадача (Macrotask, также известная как Task) — это единица работы в Event Loop браузера, которая имеет низкий приоритет и выполняется после всех микрозадач. Понимание макрозадач критично для предсказания порядка выполнения асинхронного кода.
Виды Макрозадач
Основные источники макрозадач:
-
setTimeout / setInterval
setTimeout(() => console.log('Макрозадача'), 0); -
setImmediate (Node.js, некоторые браузеры)
setImmediate(() => console.log('Макрозадача')); -
requestAnimationFrame
requestAnimationFrame(() => console.log('Макрозадача')); -
I/O операции
- Чтение/запись файлов
- Сетевые запросы
-
User events
- Клики мыши
- Нажатия клавиш
- Фокус элемента
-
DOM events
load,unloadscroll,resize
Макрозадачи vs Микрозадачи
Это главное отличие, которое нужно понимать:
console.log('1. Синхронный код');
Promise.resolve()
.then(() => console.log('2. Микрозадача (Promise)'));
setTimeout(() => {
console.log('3. Макрозадача (setTimeout)');
}, 0);
console.log('4. Синхронный код');
// Результат:
// 1. Синхронный код
// 4. Синхронный код
// 2. Микрозадача (Promise)
// 3. Макрозадача (setTimeout)
Почему именно такой порядок?
- Event Loop сначала выполняет весь синхронный код
- Затем обрабатывает ВСЕ микрозадачи (Promises, MutationObserver)
- Затем обрабатывает ОДНУ макрозадачу (setTimeout)
- Повторяет цикл
Event Loop с макрозадачами
┌─────────────────────────────┐
│ Синхронный код (Call Stack) │
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ Микрозадачи (Microtask) │ ← Promise.then()
│ │ ← MutationObserver
│ │ ← queueMicrotask()
└─────────────────────────────┘
↓
┌─────────────────────────────┐
│ Макрозадачи (Macrotask) │ ← setTimeout()
│ │ ← setInterval()
│ │ ← requestAnimationFrame()
└─────────────────────────────┘
↓
Отрисовка (Rendering)
↓
Повторить цикл
Сложный пример для понимания
console.log('1. Start');
// Макрозадача
setTimeout(() => {
console.log('2. setTimeout 1');
Promise.resolve().then(() => console.log('3. Promise в setTimeout'));
}, 0);
// Микрозадачи
Promise.resolve()
.then(() => {
console.log('4. Promise 1');
setTimeout(() => console.log('5. setTimeout в Promise'), 0);
})
.then(() => console.log('6. Promise 2'));
// Макрозадача
setTimeout(() => {
console.log('7. setTimeout 2');
}, 0);
console.log('8. End');
// Результат:
// 1. Start
// 8. End
// 4. Promise 1
// 6. Promise 2
// 2. setTimeout 1
// 3. Promise в setTimeout
// 7. setTimeout 2
// 5. setTimeout в Promise
Почему это важно
Проблема: Race conditions
let state = 'loading';
// Может выполниться в неправильном порядке!
setTimeout(() => {
state = 'loaded';
}, 0);
Promise.resolve().then(() => {
console.log(state); // 'loading', а не 'loaded'!
});
Решение: Используй микрозадачи для зависимостей
let state = 'loading';
Promise.resolve()
.then(() => { state = 'loaded'; })
.then(() => {
console.log(state); // 'loaded' — правильно!
});
Практические применения
Отложить работу с низким приоритетом:
function defer(fn: () => void) {
setTimeout(fn, 0); // Макрозадача — низкий приоритет
}
// Vs
function deferMicro(fn: () => void) {
Promise.resolve().then(fn); // Микрозадача — высокий приоритет
}
Батчинг обновлений:
let updates = [];
function scheduleUpdate(fn) {
updates.push(fn);
if (updates.length === 1) {
// Выполнить все накопленные обновления в одной макрозадаче
setTimeout(() => {
const batch = updates;
updates = [];
batch.forEach(fn => fn());
}, 0);
}
}
Ключевые моменты
- Макрозадача выполняется ПОСЛЕ всех микрозадач
- setTimeout(fn, 0) — не означает «немедленно»
- Между макрозадачами происходит отрисовка (rendering)
- Микрозадачи имеют выше приоритет чем макрозадачи
- requestAnimationFrame — макрозадача, но вызывается перед отрисовкой
Мастерство работы с Event Loop — залог написания предсказуемого асинхронного кода!