Skip to main content

Що відбувається, коли виникає помилка

Коли в коді виникає помилка, рушій створює об'єкт Error, викидає його через throw і піднімається стеком викликів, шукаючи найближчий try...catch. Якщо обробника не знайдено, виконання скрипта припиняється; якщо знайдено, програма продовжує роботу з рядка після блоку catch.

Теорія

TL;DR

  • Рушій (наприклад, V8 у Chrome та Node.js) натрапляє на ситуацію, яку не може обробити.
  • Автоматично створюється об'єкт помилки з name, message і stack.
  • Помилка викидається (throw) і піднімається вгору стеком викликів.
  • Рушій шукає найближчий try...catch; якщо в поточній функції його немає, пошук триває у функції-викликачі.
  • Без обробника помилка спливає до самого верху і виконання коду припиняється.
  • Зі спійманою помилкою програма продовжує роботу після блоку catch, а finally виконується в будь-якому випадку.

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

javascript
function test() { console.log(a); // ReferenceError } try { test(); } catch (err) { console.log("Помилку спіймано:", err.message); }

Тут помилка не призведе до падіння програми, бо її перехопив catch.

Крок 1: рушій виявляє проблему

Під час виконання коду рушій JavaScript натрапляє на ситуацію, яку не може обробити, наприклад:

javascript
console.log(a);

Змінна a не визначена. Рушій «бачить» це і створює об'єкт помилки:

javascript
ReferenceError: a is not defined

Крок 2: створюється об'єкт Error

JavaScript автоматично створює об'єкт з інформацією про помилку:

javascript
{ name: "ReferenceError", message: "a is not defined", stack: "Stack trace..." }

Він містить:

  • name, тип помилки;
  • message, текстовий опис;
  • stack, стек викликів, тобто де саме сталася помилка.

Крок 3: помилка викидається і шукає обробник

Після створення рушій «кидає» (throw) цю помилку вгору стеком викликів, тобто JavaScript шукає найближчий try...catch, який зможе її перехопити.

Якщо помилка виникає всередині блоку try, JavaScript одразу переходить до відповідного catch. Якщо всередині поточної функції try...catch немає, рушій піднімається вгору стеком викликів, до функції, яка викликала поточну, і так далі, доки не знайде обробник.

Якщо обробник не знайдено, помилка «спливає» до самого верху і виконання коду припиняється.

Крок 4: припинення виконання, якщо помилку не спіймано

Якщо помилку не спіймано, програма зупиняється:

javascript
console.log(a); console.log("Цей код не виконається");

Після ReferenceError у першому рядку виконання переривається, і другий рядок уже не буде виконано.

Крок 5: відновлення роботи і блок finally

Якщо помилку спіймано в try...catch, виконання програми продовжується після блоку catch:

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

Вивід:

javascript
Сталася помилка: Expected property name or '}' in JSON at position 2 Код продовжується...

Якщо додати блок finally, він виконається завжди, незалежно від того, була помилка чи ні:

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

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

Етапи одним поглядом

ЕтапЩо відбувається
1Виявлення проблеми
2Створення об'єкта помилки
3Викидання (throw) помилки
4Пошук обробника (try...catch)
5Переривання виконання, якщо помилку не спіймано
6Продовження роботи, якщо помилку оброблено
7Виконання блоку finally, якщо він є

Типові помилки

  • Думати, що після catch виконання повертається у місце збою. Ні, рядки в try після проблемного вже пропущені назавжди; програма продовжується з коду після всієї конструкції.
  • Очікувати, що try...catch спіймає асинхронну помилку. Виняток усередині setTimeout або в необробленому промісі виникає в іншому такті event loop, коли зовнішній try уже завершився.
  • Ігнорувати stack. Саме стек викликів показує ланцюжок функцій, який привів до збою; логувати лише message означає викидати найкорисніше.
  • Ставити return у finally. Таке значення перекриє і результат try, і викинуту помилку, тому збій просто зникне без сліду.
  • Вважати, що неспіймана помилка ламає лише один рядок. Вона зупиняє весь поточний стек викликів, тому далі не виконається нічого з цієї гілки коду.

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

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

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