Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Функція queueMicrotask()». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`queueMicrotask(callback)` додає функцію в чергу мікротасок (Microtask Queue): вона виконається після того, як відпрацює весь поточний синхронний код, але раніше за будь-яку макротаску, тобто раніше за `setTimeout`, `setInterval`, обробники подій та I/O.** За поведінкою це повний аналог `Promise.resolve().then(callback)`, але без створення об'єкта Promise, тому виклик трохи дешевший і простіший. Event Loop вичерпує чергу мікротасок повністю, включно з тими мікротасками, що додалися вже під час її обробки, і лише потім бере наступну макротаску. Функція повертає `undefined`, стандартизована в ECMAScript 2019 і доступна в усіх сучасних браузерах та в Node.js. ```javascript console.log('A'); queueMicrotask(() => console.log('B')); console.log('C'); // A, C, B ``` **Ключове:** `queueMicrotask()` ставить функцію в чергу мікротасок, яка завжди спустошується після поточного коду і до першого таймера.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`queueMicrotask(callback)` ставить передану функцію в чергу мікротасок, і вона виконається одразу після завершення поточного синхронного коду, але раніше за будь-яку макротаску.** Це найпростіший спосіб відкласти дію «на найближчий момент, коли стек спорожніє», не створюючи для цього проміс. ## Теорія ### TL;DR - `queueMicrotask(fn)` додає `fn` у Microtask Queue і повертає `undefined`. - Мікротаска виконується після того, як спорожніє Call Stack, але до першої макротаски (`setTimeout`, `setInterval`, події, I/O). - Поведінка ідентична до `Promise.resolve().then(fn)`, лише без витрат на створення об'єкта Promise. - Event Loop вичерпує чергу мікротасок повністю, разом із тими, що додалися під час її обробки. - Нескінченне додавання мікротасок блокує Event Loop: жодна макротаска не дочекається своєї черги. - Стандарт з ECMAScript 2019, підтримується всіма сучасними браузерами та Node.js. ### Швидкий приклад ```javascript console.log('A'); queueMicrotask(() => console.log('B')); console.log('C'); // Output: // A // C // B ``` Спершу виконується весь синхронний код (`A`, потім `C`). Далі Event Loop бачить, що стек порожній, і виконує мікротаску (`B`), перш ніж переходити до макротасок. ### Що саме робить `queueMicrotask()` Сигнатура гранично проста: ```javascript queueMicrotask(callback); ``` Функція робить дві речі: - додає `callback` у **чергу мікротасок**; - гарантує, що він виконається **після завершення поточної функції**, але **до** будь-якого `setTimeout`, `setInterval`, події чи іншої макротаски. Під капотом порядок такий: 1. Поточний код у Call Stack виконується до кінця. 2. Після його завершення Event Loop перевіряє **чергу мікротасок**. 3. Усі мікротаски з черги виконуються **по порядку**, одна за одною. 4. Тільки після цього береться наступна **макротаска** (наприклад, колбек `setTimeout`). ### Порядок виконання поруч із таймером ```javascript setTimeout(() => console.log('timeout'), 0); queueMicrotask(() => console.log('microtask')); console.log('sync'); // Output: // sync // microtask // timeout ``` Порядок пояснюється трьома рівнями: 1. `sync`, це синхронний код, він виконується першим; 2. `microtask`, це черга мікротасок, вона спустошується одразу після синхронного коду; 3. `timeout`, це черга макротасок, до неї Event Loop доходить в останню чергу. Навіть `setTimeout(fn, 0)` ніколи не випередить мікротаску: нульова затримка означає лише «постав у чергу макротасок якнайшвидше», а не «виконай негайно». ### Порівняння з `Promise.then` `queueMicrotask()` працює **так само**, як `Promise.resolve().then(callback)`, але **без створення об'єкта Promise**, що робить його трохи швидшим і простішим. ```javascript Promise.resolve().then(() => console.log('microtask via Promise')); queueMicrotask(() => console.log('microtask via queueMicrotask')); ``` Обидва колбеки потраплять у **чергу мікротасок** і виконаються **раніше за будь-які таймери**. Різниця лише в ціні: варіант із промісом додатково створює об'єкт Promise і ланцюжок `then`, тоді як `queueMicrotask()` просто кладе функцію в чергу. Якщо результат вам не потрібен і ланцюжок не будується, `queueMicrotask()` виражає намір точніше. ### Вкладені мікротаски і ризик заблокувати Event Loop Усі мікротаски виконуються підряд. Якщо всередині мікротаски створити нову, вона додасться в ту саму чергу і виконається **до переходу до макротаски**: ```javascript queueMicrotask(() => { console.log('A'); queueMicrotask(() => console.log('B')); }); // Output: // A // B ``` Звідси випливає небезпека: чергу мікротасок можна зробити нескінченною. ```javascript function loop() { queueMicrotask(loop); } loop(); ``` Такий код «підвісить» Event Loop: мікротаски виконуватимуться нескінченно, і жодна макротаска (`setTimeout`, кліки, рендер, мережеві колбеки) не дійде до виконання. Вкладку браузера це фактично заморозить. ### Підсумок | Властивість | Значення | | --- | --- | | Що робить | Додає функцію в чергу мікротасок | | Коли виконується | Після поточного коду, але до будь-яких макротасок | | Аналог | `Promise.resolve().then(fn)` | | Черга | Microtask Queue | | Повертає | `undefined` | | Використання | Легка і швидка альтернатива промісам для мікротасок | | Стандарт | ECMAScript 2019, усі сучасні браузери та Node.js | ### Типові помилки - **Плутати з `setTimeout(fn, 0)`.** Таймер, це макротаска, він виконається пізніше за всі мікротаски, навіть із нульовою затримкою. - **Думати, що мікротаска виконується «негайно».** Вона все одно чекає, доки поточна функція повністю відпрацює і стек спорожніє. - **Рекурсивно додавати мікротаски.** Це не «розбиття роботи на частини», а гарантоване блокування Event Loop, бо черга мікротасок не віддає керування макротаскам. - **Використовувати для важких обчислень.** Мікротаска блокує рендер так само, як синхронний код. Для розбиття важкої роботи потрібні макротаски (`setTimeout`) або окремий Worker. - **Очікувати повернене значення.** `queueMicrotask()` завжди повертає `undefined`, у ньому немає ланцюжка, як у промісі, і немає способу дізнатися результат колбека. - **Покладатися на нього для обробки помилок.** Виняток усередині колбека не потрапляє в жоден `catch`, а спливає як необроблена помилка, тому обробляти її треба всередині самої функції.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.