Як працює "мікротаска проміса"?
Що таке мікротаска
Мікротаска (microtask) - це маленька задача, яка виконується після поточного стеку викликів,
але до того, як рушій перейде до макротасок (наприклад setTimeout, setInterval, fetch тощо).
Простіше кажучи: Мікротаски - це "черга термінових задач", які виконуються одразу після поточного коду, перш ніж почнеться "наступний тик" Event Loop.
Проміси створюють мікротаски
Коли проміс переходить у стан fulfilled або rejected,
його обробники .then() / .catch() / .finally()
не виконуються одразу,
а ставляться в чергу мікротасок (Microtask Queue).
Приклад
console.log('1');
Promise.resolve().then(() => console.log('2'));
console.log('3');Результат:
1
3
2Чому так:
- Спочатку виконується весь синхронний код (у стеку викликів).
- Потім Event Loop бачить, що стек порожній,
і виконує всі мікротаски (у цьому випадку
.then()).
Де створюються мікротаски
Мікротаски створюються:
- при
.then(),.catch(),.finally()уPromise, - при
queueMicrotask(fn), - при
MutationObserver(у браузері), - при
process.nextTick()у Node.js.
Черга мікротасок і макротасок
Рушій JS обробляє події так:
- Виконує весь синхронний код (Call Stack).
- Виконує всі мікротаски, поки черга не порожня.
- Переходить до однієї макротаски (наприклад,
setTimeout). - Знову виконує всі мікротаски, що накопичилися після неї.
- І так по колу.
Приклад: порівняння з макротасками
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');Вивід:
A
D
C
BЧому:
A,D- синхронно;C- мікротаска (від проміса);B- макротаска (відsetTimeout).
Мікротаска (C) виконується раніше за таймер (B).
Приклад з кількома мікротасками
Promise.resolve().then(() => console.log('1'));
Promise.resolve().then(() => console.log('2'));
Promise.resolve().then(() => console.log('3'));
console.log('4');Вивід:
4
1
2
3Усі .then() потрапляють в одну чергу мікротасок,
і виконуються у порядку додавання,
після завершення синхронного коду (4).
Приклад: мікротаска всередині мікротаски
Promise.resolve().then(() => {
console.log('A');
Promise.resolve().then(() => console.log('B'));
});Вивід:
A
BЧому:
- Після
Aвиконується нова мікротаска (B), додана під час виконання попередньої.
Важливе правило
Після виконання кожної макротаски рушій завжди повністю виконує всі мікротаски, перш ніж узяти наступну макротаску.
Проста аналогія
Уяви, що Event Loop - це черга в кафе.
- "Макротаски" - це звичайні замовлення (великі).
- "Мікротаски" - це швидка решта і розрахунок.
Бариста робить замовлення (синхронний код), потім видає всю решту (мікротаски), і лише потім переходить до наступного клієнта (нової макротаски).
Підсумок
| Тип задачі | Приклади | Коли виконується |
|---|---|---|
| Мікротаски | .then(), .catch(), .finally(), queueMicrotask() | Після поточного коду, до наступної макротаски |
| Макротаски | setTimeout, setInterval, fetch, події DOM | Після всіх мікротасок поточного тика |
Проміси завжди використовують мікротаски, тому їхні колбеки виконуються раніше, ніж таймери.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.