Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Помилки всередині функцій». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Помилки всередині функції обробляють блоком `try...catch`: код, який може впасти, кладемо в `try`, а в `catch` вирішуємо, що робити далі: залогувати, повернути безпечне значення чи прокинути помилку вище.** У `async` функціях працює той самий `try...catch`, але навколо `await`; якщо `await` не використовується, помилки промісу ловить `.catch()`. Важливо не глушити помилку мовчки: або обробіть її осмислено, або киньте далі через `throw`, щоб рішення ухвалив код, який вас викликав. ```javascript function divide(a, b) { try { if (b === 0) { throw new Error('Division by zero is not possible'); } return a / b; } catch (error) { console.error('Error:', error.message); return null; // safe fallback value } } ``` **Ключове:** ловіть помилку точково там, де реально можете щось із нею зробити, інакше прокидайте її вище.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Помилки всередині функції обробляють через `try...catch`, а в асинхронному коді через той самий `try...catch` навколо `await` або через `.catch()` у промісах.** Задача обробки не в тому, щоб приховати збій, а в тому, щоб функція поводилася передбачувано: повернула безпечне значення або прокинула зрозумілу помилку вище. ## Теорія ### TL;DR - `try...catch` захищає синхронний код: усе, що в `try`, виконується «під захистом», а при помилці керування переходить у `catch`. - В `async` функціях `try...catch` ставлять усередині, навколо `await`. - Без `await` помилки промісу ловить `.catch()` у ланцюжку. - Помилку можна не тільки зловити, а й прокинути вище через `throw new Error(...)`. - Використовуйте `try...catch` точково, там, де ви справді очікуєте збій. - Не глушіть помилки без логування і повертайте передбачуване значення при збої. ### Швидкий приклад ```javascript function divide(a, b) { try { if (b === 0) { throw new Error('Division by zero is not possible'); } return a / b; } catch (error) { console.error('Error:', error.message); return null; // safe fallback value } } console.log(divide(10, 0)); // Error: Division by zero is not possible -> null ``` Що тут відбувається: - усе, що всередині `try`, виконується «під захистом»; - якщо виникає помилка, виконання переходить у `catch`; - після цього програма не падає, а функція повертає передбачуване `null`. ### Синхронна обробка помилок `try...catch` використовують тоді, коли помилка може статися в момент виконання функції: некоректний аргумент, невдалий розбір рядка, звернення до властивості `null`. Блок `catch` отримує об'єкт помилки, у якого є щонайменше `name`, `message` і `stack`. Важливо розуміти межі: `try...catch` ловить лише те, що кинуто синхронно всередині блока. Помилка з колбека, який виконається пізніше (наприклад, у `setTimeout`), уже не потрапить у цей `catch`, бо на момент її виникнення блок давно завершився. ### Асинхронні помилки в `async/await` Для `async` функцій `try...catch` ставлять усередині асинхронного блока, навколо `await`. Тоді відхилений проміс перетворюється на звичайний виняток, який ловиться на місці: ```javascript async function fetchUser(id) { try { const res = await fetch(`/api/users/${id}`); if (!res.ok) throw new Error('User not found'); return await res.json(); } catch (error) { console.error('Request failed:', error.message); return null; } } ``` Зверніть увагу на перевірку `res.ok`: `fetch` відхиляє проміс лише при мережевій помилці, а відповідь зі статусом 404 або 500 для нього цілком успішна. Тож помилку HTTP треба кидати вручну. ### Помилки в промісах Якщо `await` не використовується, помилки ловлять через `.catch()` наприкінці ланцюжка. Один `.catch()` покриває всі попередні `.then()`: ```javascript fetch('/api/data') .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error('Error:', err)); ``` Ланцюжок без `.catch()` дає необроблене відхилення (`unhandled rejection`), яке в Node.js може завершити процес. ### Створення і проброс помилок вручну Іноді помилку треба не тільки зловити, а й передати вище, додавши контекст. Тоді в `catch` кидають нову помилку: ```javascript function parseJSON(str) { try { return JSON.parse(str); } catch (error) { throw new Error('Invalid JSON: ' + error.message); } } try { parseJSON('{invalid}'); } catch (e) { console.error('Caught at the top level:', e.message); } ``` Так низькорівнева помилка розбору перетворюється на зрозуміле повідомлення, а рішення, що робити далі, ухвалює код, який викликав функцію. ### Добрі практики - Використовуйте `try...catch` точково, там, де реально очікуєте помилку, а не навколо всього тіла функції. - Не глушіть помилки без логування: порожній `catch` це найшвидший спосіб втратити день на дебаг. - Повертайте при збої передбачуване значення: `null`, `{}`, `false`, і документуйте це. - Для серверних функцій логуйте через `logger`, Sentry або хоча б `console.error`. - Для чистих функцій краще кидати помилку, а не логувати: нехай рішення ухвалює код, що викликав. ### Типові помилки - **Порожній `catch`.** `catch (e) {}` робить збій невидимим, а програму, яка «просто нічого не робить», неможливо діагностувати. - **`try...catch` навколо асинхронного колбека.** Обгортання `setTimeout` або старого колбека у `try` не ловить нічого: помилка станеться після виходу з блока. - **Забути `await` перед промісом усередині `try`.** Без `await` функція поверне проміс, а відхилення пролетить повз `catch`. - **Покладатися на те, що `fetch` сам кине помилку на 404.** Він відхиляється лише при мережевому збої, тож статус треба перевіряти вручну. - **Кидати рядок замість `Error`.** `throw 'oops'` позбавляє вас стеку викликів і ламає код, який очікує `error.message`. - **Ловити помилку там, де ви не можете нічого з нею зробити.** Якщо функція не вміє відновитися, чесніше прокинути помилку вище, ніж повернути тихий `null`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.