Skip to main content

Конструкція try...catch

try...catch це конструкція обробки винятків: усе, що може зламатися, кладуть у блок try, а реакцію на поломку в блок catch. Замість того щоб зупинити весь скрипт, движок передає керування в catch разом з об'єктом помилки, і програма продовжує працювати.

Теорія

TL;DR

  • try містить код, у якому можлива помилка, catch (error) отримує об'єкт помилки й обробляє її.
  • Якщо помилки немає, блок catch пропускається повністю.
  • Рядки в try після місця помилки не виконуються, а код після всієї конструкції виконується далі.
  • Необов'язковий finally спрацьовує завжди: і після успіху, і після помилки.
  • throw дозволяє згенерувати виняток вручну, і його ловить той самий catch.
  • Ловляться лише runtime-помилки синхронного коду всередині блоку.

Швидкий приклад

javascript
try { // код, у якому може статися помилка JSON.parse("not valid json"); } catch (error) { // виконається, лише якщо помилка виникла console.log("Спіймали:", error.message); }

Синтаксис у загальному вигляді:

javascript
try { // код, у якому може статися помилка } catch (error) { // код, який виконається, якщо помилка виникла }

Як це працює

  1. Код у блоці try виконується рядок за рядком.
  2. Якщо всередині try виникає помилка, виконання try обривається, і керування передається в catch.
  3. Якщо помилок немає, блок catch пропускається.
  4. Після try...catch програма продовжує виконання далі.

Приклад 1. Без try...catch скрипт падає:

javascript
console.log("Початок"); JSON.parse("not valid json"); // SyntaxError console.log("Кінець"); // не виконається

Вивід:

text
Uncaught SyntaxError: Unexpected token 'o', "not valid json" is not valid JSON

Приклад 2. З try...catch програма працює далі:

javascript
console.log("Початок"); try { JSON.parse("not valid json"); } catch (err) { console.log("Помилку спіймано:", err.message); } console.log("Кінець");

Вивід:

text
Початок Помилку спіймано: Unexpected token 'o', "not valid json" is not valid JSON Кінець

Помилка оброблена, скрипт не впав.

Блок finally

До конструкції можна додати третій блок, finally. Він виконується завжди, незалежно від того, була помилка чи ні.

javascript
try { console.log("Виконуємо try"); throw new Error("Помилка!"); } catch (err) { console.log("Спіймали:", err.message); } finally { console.log("Цей код виконається в будь-якому разі"); }

Вивід:

text
Виконуємо try Спіймали: Помилка! Цей код виконається в будь-якому разі

Найчастіше finally використовують для прибирання ресурсів: закрити з'єднання, зупинити таймер, видалити тимчасові файли, зняти стан завантаження в інтерфейсі.

Якщо змінна помилки не потрібна, з ES2019 її можна не оголошувати взагалі:

javascript
try { JSON.parse(raw); } catch { // сам факт помилки важливіший за її текст return null; }

Ручний виняток через throw

try...catch часто застосовують разом з оператором throw, щоб згенерувати виняток самостійно:

javascript
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:

javascript
try { try { throw new TypeError("Невірний тип"); } catch (e) { console.log("Внутрішній catch:", e.message); throw new Error("Нова помилка"); } } catch (e) { console.log("Зовнішній catch:", e.message); }

Вивід:

text
Внутрішній 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 проти синтаксичних помилок. Скрипт з битим синтаксисом не запуститься взагалі, ловити там нічого.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.