Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Ключове слово async». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`async` перетворює звичайну функцію на асинхронну: вона завжди повертає `Promise`, а всередині неї дозволено `await`.** Значення з `return` автоматично загортається в `Promise.resolve(value)`, а `throw` всередині перетворюється на `Promise.reject(error)`. Сам по собі `async` нічого не прискорює і не робить код паралельним, він лише задає протокол: результат приходить промісом. ```javascript async function hello() { return 'Привіт!'; } hello().then(console.log); // Привіт! ``` **Ключове:** `async` = «функція повертає проміс і може чекати через `await`».Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Ключове слово `async` перед оголошенням функції означає, що ця функція завжди повертає `Promise`, а всередині неї можна використовувати `await`.** Повернене значення автоматично загортається в `Promise.resolve(value)`, тому виклик такої функції завжди можна продовжити через `.then()` або `await`. ## Теорія ### TL;DR - `async function myFunc() { ... }` завжди повертає `Promise`, навіть якщо в тілі немає жодного проміса. - `return value` всередині стає `Promise.resolve(value)`. - `throw error` всередині стає `Promise.reject(error)`. - `await` дозволено тільки всередині `async`-функцій (або як top-level await у модулі). - `await` призупиняє саму функцію, але не блокує потік: JS у цей час виконує інші задачі. - Помилки зручно ловити через `try...catch` замість `.catch()`. ### Швидкий приклад ```javascript async function myFunc() { return 42; } myFunc().then(console.log); // 42 // те саме, що: function myFunc() { return Promise.resolve(42); } ``` ### Що саме додає `async` Ключове слово `async` перед оголошенням функції: ```javascript async function myFunc() { ... } ``` означає, що: 1. **Функція завжди повертає `Promise`.** 2. Усередині неї можна використовувати `await`. 3. Повернене значення автоматично загортається в `Promise.resolve(value)`. **Приклад 1, звичайне значення перетворюється на проміс** ```javascript async function hello() { return 'Привіт!'; } hello().then(console.log); ``` Вивід: ```text Привіт! ``` Під капотом це те саме, що: ```javascript function hello() { return Promise.resolve('Привіт!'); } ``` **Приклад 2, викидання помилки перетворюється на `reject`** ```javascript async function fail() { throw new Error('Помилка!'); } fail().catch(err => console.error(err.message)); ``` Вивід: ```text Помилка! ``` Якщо всередині `async`-функції стається `throw`, проміс автоматично **відхиляється (`Promise.reject`)**. **Приклад 7, стрілкова функція.** Писати можна і стрілкові async-функції: ```javascript const load = async () => { const res = await fetch('/data'); return res.json(); }; ``` ### Як працює `await` `await` можна використовувати **тільки всередині `async`-функцій**. Він призупиняє виконання функції, доки проміс не виконається. **Приклад 3, використання `await`** ```javascript async function getData() { console.log('Завантажуємо...'); const res = await fetch('https://api.github.com/users/octocat'); const user = await res.json(); console.log('Готово:', user.login); } getData(); ``` При цьому сам виклик `getData()` повертає **проміс**, тож його теж можна «дочекатися»: ```javascript await getData(); ``` (тільки в `async`-контексті або з top-level await). Коли інтерпретатор зустрічає `await somePromise`, він: 1. **призупиняє** виконання поточної функції; 2. чекає, доки проміс перейде у стан `fulfilled` або `rejected`; 3. відновлює виконання: - повертаючи значення (`resolve`); - або викидаючи помилку (`reject`). **Приклад 4, послідовне виконання** ```javascript async function steps() { console.log('1'); await new Promise(res => setTimeout(res, 1000)); console.log('2'); await new Promise(res => setTimeout(res, 1000)); console.log('3'); } steps(); ``` Вивід: ```text 1 (через 1 секунду) 2 (через 1 секунду) 3 ``` Завдяки `await` код виглядає як синхронний, але насправді він неблокуючий: JS продовжує виконувати інші задачі в цей час. ### Послідовно чи паралельно Якщо не ставити `await` одразу, проміси почнуть виконуватися **паралельно**. **Приклад 5, паралельне виконання промісів** ```javascript async function parallel() { const p1 = fetch('/api/user'); const p2 = fetch('/api/posts'); const [user, posts] = await Promise.all([p1, p2]); console.log('Обидві відповіді отримано'); } ``` Так ви не чекаєте кожен запит окремо, а обидва виконуються одночасно. Послідовний варіант (`await fetch(...)` двічі поспіль) відпрацює приблизно за суму часів, паралельний, за час найповільнішого запиту. ### Обробка помилок В `async`-функціях помилки зручно ловити через `try/catch` замість `.catch()`. **Приклад 6, комбінування з `try...catch`** ```javascript async function loadData() { try { const res = await fetch('/bad-url'); const data = await res.json(); console.log('OK:', data); } catch (err) { console.error('Помилка:', err.message); } } ``` `try...catch` ловить і синхронні винятки в тілі функції, і відхилені проміси, які ви дочекалися через `await`. ### Підсумок > Уявіть, що `async` - це **обіцянка**, а `await` - це **пауза**, доки обіцянку не буде виконано. > Тобто `async` робить функцію такою, що «дає обіцянку», а `await` дозволяє «дочекатися» результату цієї обіцянки, але без блокування інших процесів. | Особливість | Що робить | | --- | --- | | `async` | робить функцію такою, що повертає `Promise` | | `await` | «зупиняє» виконання до завершення проміса | | `return value` | перетворюється на `Promise.resolve(value)` | | `throw error` | перетворюється на `Promise.reject(error)` | | Помилки | можна ловити через `try...catch` | | Використання | тільки всередині `async` (або top-level await) | ### Типові помилки - **Думати, що `async` прискорює код.** Він лише змінює тип результату на `Promise`, обчислення від цього не стають паралельними. - **`await` у циклі для незалежних запитів.** Такий код стає послідовним; для незалежних операцій потрібен `Promise.all`. - **Викликати `async`-функцію і не обробляти її проміс.** Помилка всередині перетвориться на unhandled rejection, і ви її не побачите. - **Ставити `await` поза `async`-функцією** у звичайному скрипті: це SyntaxError. Top-level await працює лише в модулях. - **Забувати, що `return` всередині `try` з `await` відрізняється від `return promise`.** Без `await` помилку проміса не спіймає локальний `catch`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.