Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Помилки в async». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Будь-яка **`async`-функція** завжди повертає проміс. Якщо всередині неї викидається помилка (`throw`), проміс переходить у стан `rejected`. **Ключове:** помилки можна обробляти двома способами - через `try...catch` усередині самої функції або через `.catch()` зовні при виклику.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Головне правило > Будь-яка `async`-функція **завжди повертає проміс**. > Якщо всередині неї викидається помилка (`throw`), то проміс переходить у стан `rejected`. Отже, помилки можна обробляти **двома способами**: 1. через `try...catch` усередині самої функції; 2. через `.catch()` зовні при виклику. --- ## 1. Обробка через `try...catch` (усередині функції) Це **найзрозуміліший і найзвичніший спосіб** - схожий на синхронний код. ```javascript async function getData() { try { const res = await fetch('https://api.github.com/404'); // помилка мережі const data = await res.json(); console.log('Отримано:', data); } catch (error) { console.error('Помилка всередині async:', error.message); } } getData(); ``` **Вивід:** ```javascript Помилка всередині async: Failed to fetch ``` `try...catch` "ловить": - помилки, викинуті через `throw`; - відхилені проміси, на яких стоїть `await`. --- ## Як це працює `await` під капотом робить `try { ... } catch { ... }` для промісу, який може завершитися з помилкою (`reject`). ```javascript const result = await Promise.reject('помилка'); // викине виняток → перейде в блок catch ``` --- ## 2. Обробка через `.catch()` (зовні функції) Оскільки `async`-функція повертає `Promise`, помилку можна обробити звичайним методом `.catch()`: ```javascript async function getUser() { const res = await fetch('https://wrong.url'); return res.json(); } getUser() .then(console.log) .catch(err => console.error('Помилка зовні:', err.message)); ``` **Вивід:** ```javascript Помилка зовні: Failed to fetch ``` Відмінність від `try...catch`: тут помилка обробляється **при виклику**, а не всередині функції. --- ## 3. Приклад з ручним `throw` ```javascript async function example() { const data = await Promise.resolve('OK'); if (!data) throw new Error('Немає даних!'); return data; } example() .then(console.log) .catch(err => console.error(err.message)); ``` **Вивід:** ```javascript OK ``` Якщо умова спрацює, `throw` перетвориться на `Promise.reject()`. --- ## 4. Комбінація `try...catch` + повторний `throw` Іноді потрібно **обробити помилку частково**, але передати її далі - наприклад, щоб залогувати. ```javascript async function processData() { try { const res = await fetch('https://wrong.url'); return await res.json(); } catch (err) { console.error('Помилка запиту:', err.message); throw new Error('Помилка при обробці даних'); } } processData().catch(err => console.error('Фінальна помилка:', err.message)); ``` **Вивід:** ```javascript Помилка запиту: Failed to fetch Фінальна помилка: Помилка при обробці даних ``` --- ## 5. Обробка кількох помилок підряд Можна використовувати кілька `try...catch` для різних етапів: ```javascript async function pipeline() { try { const res = await fetch('/api/data'); try { const data = await res.json(); console.log('Дані:', data); } catch (err) { console.error('Помилка парсингу JSON:', err.message); } } catch (err) { console.error('Помилка запиту:', err.message); } } ``` Такий підхід корисний, коли потрібно обробити різні рівні помилок окремо. --- ## 6. Обробка без `try...catch` (через утиліту) Іноді зручніше використовувати допоміжну функцію: ```javascript const to = (promise) => promise.then(data => [null, data]).catch(err => [err]); async function run() { const [err, data] = await to(fetch('/api/user').then(r => r.json())); if (err) return console.error('Помилка:', err.message); console.log(data); } ``` Такий патерн часто використовують у Node.js, щоб не писати `try...catch` на кожному кроці. --- ## 7. Глобальне перехоплення необроблених помилок Якщо забули `.catch()` або `try...catch`, помилку можна перехопити глобально: ```javascript window.addEventListener('unhandledrejection', (event) => { console.error('Необроблений проміс:', event.reason); }); ``` Це аналог `try...catch` для всіх промісів, у яких немає `.catch()`. --- ## Проста аналогія > Уяви `async`-функцію як квест. > > - `await` - це "завдання", яке може провалитися; > - `try...catch` - це "страховка": якщо провал - ти ловиш помилку і вирішуєш, що робити; > - `.catch()` зовні - це "гейм-майстер", який ловить фатальні помилки, якщо гравець не впорався. --- ## ПІДСУМОК | Спосіб | Де ловить помилку | Приклад | |---|---|---| | `try...catch` | усередині `async`-функції | `try { await ... } catch (e) { ... }` | | `.catch()` | при виклику функції | `myAsync().catch(e => ...)` | | **Глобальне перехоплення** | для всіх необроблених | `window.addEventListener('unhandledrejection', ...)` | | **Патерн** `[err, data]` | через обгортку | `const [err, res] = await to(promise)` |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.