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