Конструкція try...catch
try...catch це конструкція обробки винятків: усе, що може зламатися, кладуть у блок try, а реакцію на поломку в блок catch. Замість того щоб зупинити весь скрипт, движок передає керування в catch разом з об'єктом помилки, і програма продовжує працювати.
Теорія
TL;DR
tryмістить код, у якому можлива помилка,catch (error)отримує об'єкт помилки й обробляє її.- Якщо помилки немає, блок
catchпропускається повністю. - Рядки в
tryпісля місця помилки не виконуються, а код після всієї конструкції виконується далі. - Необов'язковий
finallyспрацьовує завжди: і після успіху, і після помилки. throwдозволяє згенерувати виняток вручну, і його ловить той самийcatch.- Ловляться лише runtime-помилки синхронного коду всередині блоку.
Швидкий приклад
try {
// код, у якому може статися помилка
JSON.parse("not valid json");
} catch (error) {
// виконається, лише якщо помилка виникла
console.log("Спіймали:", error.message);
}Синтаксис у загальному вигляді:
try {
// код, у якому може статися помилка
} catch (error) {
// код, який виконається, якщо помилка виникла
}Як це працює
- Код у блоці
tryвиконується рядок за рядком. - Якщо всередині
tryвиникає помилка, виконанняtryобривається, і керування передається вcatch. - Якщо помилок немає, блок
catchпропускається. - Після
try...catchпрограма продовжує виконання далі.
Приклад 1. Без try...catch скрипт падає:
console.log("Початок");
JSON.parse("not valid json"); // SyntaxError
console.log("Кінець"); // не виконаєтьсяВивід:
Uncaught SyntaxError: Unexpected token 'o', "not valid json" is not valid JSONПриклад 2. З try...catch програма працює далі:
console.log("Початок");
try {
JSON.parse("not valid json");
} catch (err) {
console.log("Помилку спіймано:", err.message);
}
console.log("Кінець");Вивід:
Початок
Помилку спіймано: Unexpected token 'o', "not valid json" is not valid JSON
КінецьПомилка оброблена, скрипт не впав.
Блок finally
До конструкції можна додати третій блок, finally. Він виконується завжди, незалежно від того, була помилка чи ні.
try {
console.log("Виконуємо try");
throw new Error("Помилка!");
} catch (err) {
console.log("Спіймали:", err.message);
} finally {
console.log("Цей код виконається в будь-якому разі");
}Вивід:
Виконуємо try
Спіймали: Помилка!
Цей код виконається в будь-якому разіНайчастіше
finallyвикористовують для прибирання ресурсів: закрити з'єднання, зупинити таймер, видалити тимчасові файли, зняти стан завантаження в інтерфейсі.
Якщо змінна помилки не потрібна, з ES2019 її можна не оголошувати взагалі:
try {
JSON.parse(raw);
} catch {
// сам факт помилки важливіший за її текст
return null;
}Ручний виняток через throw
try...catch часто застосовують разом з оператором throw, щоб згенерувати виняток самостійно:
function divide(a, b) {
if (b === 0) throw new Error("Ділення на нуль!");
return a / b;
}
try {
console.log(divide(10, 0));
} catch (e) {
console.log("Помилка:", e.message);
}Кидати можна будь-яке значення, але на практиці кидають об'єкт Error або його нащадка: тоді є name, message і stack, а instanceof дозволяє відрізняти типи помилок у catch.
Особливості поведінки та вкладені блоки
| Поведінка | Опис |
|---|---|
catch ловить лише runtime-помилки | Синтаксичні помилки самого скрипта (SyntaxError на етапі парсингу) не перехоплюються |
Помилка всередині catch не ловиться тим самим try | Її треба загорнути в другий try...catch |
try...catch може бути вкладеним | Різні типи помилок обробляються на різних рівнях |
Приклад 3. Вкладені try...catch:
try {
try {
throw new TypeError("Невірний тип");
} catch (e) {
console.log("Внутрішній catch:", e.message);
throw new Error("Нова помилка");
}
} catch (e) {
console.log("Зовнішній catch:", e.message);
}Вивід:
Внутрішній catch: Невірний тип
Зовнішній catch: Нова помилкаПідсумкова таблиця елементів
| Елемент | Призначення |
|---|---|
try | Код, де можлива помилка |
catch | Обробляє помилку, якщо вона виникла |
error | Змінна, у якій зберігається об'єкт помилки |
finally | Виконується завжди, після try і catch |
throw | Генерує виняток, який ловить catch |
Типові помилки
- Чекати, що
try...catchспіймає помилку з асинхронного колбека. Виняток усерединіsetTimeoutабо обробника події виникає вже в іншому такті event loop, коли блокtryдавно завершився. Обробляти треба всередині самого колбека. - Забувати про
await.try { doAsync(); } catch {}нічого не спіймає, бо функція лише повертає promise. Потрібенtry { await doAsync(); } catch {}або.catch()у ланцюжку promise. - Порожній
catch. Мовчазне поглинання помилки ховає баг: як мінімум логуйтеerrorабо кидайте далі. - Загортати в
tryпів файлу. Чим більший блок, тим важче зрозуміти, що саме зламалося, і тим легше випадково проковтнути стороннє падіння. returnуfinally. Він перекриває значення, повернуте зtryабоcatch, і навіть «гасить» кинуту помилку, тому так робити не варто.- Розраховувати на
try...catchпроти синтаксичних помилок. Скрипт з битим синтаксисом не запуститься взагалі, ловити там нічого.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.