Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Чому await зупиняє лише поточну функцію». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`await` не блокує потік виконання JavaScript, він призупиняє лише ту `async`-функцію, у якій стоїть.** Рушій виконує код в одному потоці, але керує задачами через черги Event Loop, тому на `await` він не «засинає»: решту тіла функції він загортає в мікротаску, звільняє стек викликів і повертає керування Event Loop. Поки проміс не завершиться, продовжують працювати інші функції, обробники подій і таймери. Коли проміс переходить у `fulfilled` або `rejected`, мікротаска виконується і функція відновлюється рівно з того місця, де стояв `await`. ```javascript async function task() { console.log('start'); await new Promise(r => setTimeout(r, 2000)); console.log('end'); } task(); console.log('this line runs right away'); // start, this line runs right away, (2 s) end ``` **Ключове:** `await`, це асинхронна пауза однієї функції через чергу мікротасок, а не блокування потоку.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`await` не блокує потік виконання JavaScript, він призупиняє лише ту `async`-функцію, у якій стоїть.** Решта програми, обробники подій, таймери й інші `async`-функції продовжують працювати, бо `await` віддає керування назад у Event Loop. ## Теорія ### TL;DR - JavaScript виконує код в одному потоці, але керує задачами через черги Event Loop. - `await` не зупиняє цей потік, він «заморожує» тільки поточну `async`-функцію. - Решту тіла функції рушій загортає в мікротаску, яка виконається після завершення промісу. - Стек викликів звільняється, тому інший код (таймери, події, інші функції) виконується далі. - Коли проміс переходить у `fulfilled` або `rejected`, функція продовжується рівно з місця `await`. - Це асинхронна пауза, а не блокування: жодних потоків ОС чи `sleep` тут немає. ### Швидкий приклад ```javascript async function task() { console.log('Початок'); await new Promise(r => setTimeout(r, 2000)); console.log('Кінець'); } task(); // Цей рядок виконається одразу, рушій не заблокований console.log('Цей код виконується одразу!'); ``` Вивід: ```text Початок Цей код виконується одразу! (через 2 с) Кінець ``` `await` призупиняє тільки функцію `task()`, а основний код іде далі. JS не «зависає»: усередині `task()` просто створюється мікротаска, яка повернеться в чергу після спрацювання таймера. ### Що відбувається під капотом Коли рушій зустрічає `await promise`, відбувається таке: 1. Виконання поточної `async`-функції призупиняється. 2. Рушій створює мікротаску (callback), яка має продовжити функцію після завершення промісу. 3. Керування повертається в Event Loop, стек викликів звільняється. 4. Рушій виконує інші задачі: інші функції, обробники подій, таймери тощо. 5. Коли проміс завершено (`fulfilled` або `rejected`), мікротаска виконується і функція відновлюється саме з того рядка, де стояв `await`. Усе це реалізовано через чергу мікротасок (`PromiseJobs`). Ніяких додаткових потоків чи справжнього `sleep` рушій не використовує. ### Крок за кроком в Event Loop | Етап | Що відбувається | | --- | --- | | 1 | `task()` потрапляє в Call Stack і виконує код до `await` | | 2 | На `await` функція «заморожується», створюється мікротаска | | 3 | Стек очищується, інші скрипти продовжують виконуватися | | 4 | Коли проміс завершується, мікротаска повертається в чергу | | 5 | Після поточного тіку Event Loop виконується решта коду `task()` | Якби `await` справді блокував потік, увесь JavaScript «завис» би на ці 2 секунди: не спрацював би жоден обробник подій і жоден `setTimeout`. Але такого не стається: поки `task()` чекає, Event Loop спокійно обробляє інші події. ### Паралельні async-функції не чекають одна одну ```javascript async function foo() { console.log('foo start'); await new Promise(res => setTimeout(res, 1000)); console.log('foo end'); } async function bar() { console.log('bar start'); await new Promise(res => setTimeout(res, 500)); console.log('bar end'); } foo(); bar(); console.log('main thread'); ``` Вивід: ```text foo start bar start main thread (через 0.5 с) bar end (через 1 с) foo end ``` `await` не заважає виконанню інших функцій. Кожна функція просто «заморожується» до свого промісу, а потім продовжує роботу незалежно від сусідньої. ### Мікротаска відновлення і порядок виводу ```javascript async function demo() { console.log('A'); await Promise.resolve(); console.log('B'); } demo(); console.log('C'); ``` Результат: ```text A C B ``` Чому саме так: - `A` виконується синхронно, до `await`; - `await` зупиняє функцію і ставить її продовження (`B`) у чергу мікротасок; - основний код доходить до `C`; - і лише коли стек порожній, рушій виконує мікротаски, тобто `B`. > Проста аналогія: `async`-функція, це серіал. На `await` конкретний серіал ставиться на паузу, але інші канали продовжують мовлення. Коли потрібний проміс готовий, серія йде далі рівно з того кадру, на якому зупинилася. ### Що await робить і чого не робить | Що робить `await` | Чого не робить | | --- | --- | | Призупиняє лише поточну `async`-функцію | Не блокує потік JavaScript | | Повертає керування в Event Loop | Не заважає іншим задачам виконуватися | | Після завершення промісу відновлює виконання | Не «заморожує» весь застосунок | | Реалізований через мікротаски (`PromiseJobs`) | Не використовує потоки ОС чи `sleep` | ### Типові помилки - Вважати, що `await` зупиняє всю сторінку, і через це уникати його в коді, який реагує на події. - Плутати паузу функції з блокуванням: справжнє блокування дає синхронний цикл `while (Date.now() < end) {}`, і саме він «вішає» вкладку, бо не віддає стек. - Ставити `await` у циклі там, де запити незалежні: функція чекає їх послідовно, хоча можна запустити все разом через `Promise.all()`. - Очікувати, що два `await` підряд виконаються паралельно. Вони строго послідовні: другий стартує лише після завершення першого. - Забувати, що після `await` код продовжується вже в мікротасці, тому порядок логів відрізняється від синхронного читання зверху вниз.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.