Мікрозадачі (microtasks)
Мікрозадачі (microtasks) це невеликі задачі, які виконуються одразу після поточного коду (поточної макрозадачі) і до того, як почнеться наступна макрозадача з черги. Вони утворюють окрему структуру, чергу мікрозадач (Microtask Queue).
Теорія
TL;DR
- Мікрозадача це колбек, який Event Loop виконує після поточного коду, але раніше за будь-яку макрозадачу.
- Основні джерела:
Promise.then,Promise.catch,queueMicrotask,MutationObserver. - Черга мікрозадач вичерпується повністю, а з черги макрозадач за оберт береться лише одна задача.
- Пріоритет мікрозадач вищий, тому
Promise.thenзавжди випереджаєsetTimeout(..., 0). - Нескінченне породження мікрозадач «заморожує» Event Loop: макрозадачі і рендеринг не отримають керування.
- Порядок: стек, усі мікрозадачі, наступна макрозадача.
Швидкий приклад
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');Підсумковий порядок виводу:
1
4
3
2Ключова ідея
У JavaScript є два рівні задач:
| Тип | Приклади | Коли виконується |
|---|---|---|
| Макрозадачі (Tasks) | setTimeout, setInterval, події DOM, мережеві колбеки | Після очищення стека |
| Мікрозадачі (Microtasks) | Promise.then, Promise.catch, queueMicrotask, MutationObserver | Одразу після поточної задачі, до наступної макрозадачі |
Тобто після виконання поточного коду (наприклад, функції) Event Loop спершу перевіряє чергу мікрозадач. Якщо в ній є задачі, вони виконуються всі поспіль, доки черга не спорожніє.
Покроковий розбір прикладу
console.log('1')виконується одразу. Вивід:1setTimeout(..., 0): колбек потрапляє у чергу макрозадач (task queue).Promise.then(...): колбек потрапляє у чергу мікрозадач.console.log('4')виконується одразу. Вивід:4- Поточний стек порожній, тому виконуються всі мікрозадачі, тобто
console.log('3'). - І лише після цього виконуються макрозадачі, тобто
console.log('2').
Що створює мікрозадачі
| Джерело | Приклад |
|---|---|
| Promise | Promise.resolve().then(...) |
| queueMicrotask() | queueMicrotask(() => { ... }) |
| MutationObserver | Відстеження змін DOM |
Сюди ж належить і async/await: продовження після await планується як мікрозадача.
Відмінність мікрозадач від макрозадач
| Властивість | Мікрозадачі | Макрозадачі |
|---|---|---|
| Черга | Microtask Queue | Task Queue |
| Приклади | Promise.then, queueMicrotask | setTimeout, setInterval, click |
| Пріоритет | Вищий, виконуються раніше | Нижчий |
| Коли виконуються | Після поточного коду, але до наступної події | Після всіх мікрозадач |
Обережно з мікрозадачами
Якщо нескінченно додавати нові мікрозадачі всередині then, рушій ніколи не дійде до наступної макрозадачі, і вийде «заморожений» Event Loop:
function loop() {
Promise.resolve().then(loop);
}
loop(); // браузер зависнеСтек при цьому не переповниться, бо кожна мікрозадача завершується коректно. Просто черга мікрозадач ніколи не стане порожньою, тож ані таймери, ані обробники подій, ані перемальовування сторінки не отримають свого часу.
Коротко про терміни
| Термін | Опис |
|---|---|
| Microtask | Маленька задача, що виконується після поточного коду і до наступної макрозадачі |
| Черга мікрозадач | Зберігає колбеки Promise.then, queueMicrotask і подібні |
| Пріоритет | Вищий, ніж у макрозадач |
| Порядок Event Loop | Стек, потім усі мікрозадачі, потім наступна макрозадача |
Типові помилки
- Ставити
Promise.thenіsetTimeout(..., 0)в один ряд. Промис це мікрозадача, і він виконається раніше завжди, незалежно від порядку в коді. - Вважати, що мікрозадача це «швидший таймер». Це інша черга з іншим пріоритетом, а не менша затримка.
- Рекурсивно планувати мікрозадачі для фонової роботи. Так ви блокуєте рендеринг; для порційної роботи беріть
setTimeoutабоrequestIdleCallback. - Забувати, що продовження після
awaitтеж мікрозадача. Через це код післяawaitвиконується пізніше, ніж очікують, але все одно раніше за таймери. - Плутати чергу мікрозадач зі стеком викликів. Мікрозадачі виконуються лише тоді, коли стек уже порожній.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.