Що відбувається, коли виникає помилка
Коли в коді виникає помилка, рушій створює об'єкт Error, викидає його через throw і піднімається стеком викликів, шукаючи найближчий try...catch. Якщо обробника не знайдено, виконання скрипта припиняється; якщо знайдено, програма продовжує роботу з рядка після блоку catch.
Теорія
TL;DR
- Рушій (наприклад, V8 у Chrome та Node.js) натрапляє на ситуацію, яку не може обробити.
- Автоматично створюється об'єкт помилки з
name,messageіstack. - Помилка викидається (
throw) і піднімається вгору стеком викликів. - Рушій шукає найближчий
try...catch; якщо в поточній функції його немає, пошук триває у функції-викликачі. - Без обробника помилка спливає до самого верху і виконання коду припиняється.
- Зі спійманою помилкою програма продовжує роботу після блоку
catch, аfinallyвиконується в будь-якому випадку.
Швидкий приклад
function test() {
console.log(a); // ReferenceError
}
try {
test();
} catch (err) {
console.log("Помилку спіймано:", err.message);
}Тут помилка не призведе до падіння програми, бо її перехопив catch.
Крок 1: рушій виявляє проблему
Під час виконання коду рушій JavaScript натрапляє на ситуацію, яку не може обробити, наприклад:
console.log(a);Змінна a не визначена. Рушій «бачить» це і створює об'єкт помилки:
ReferenceError: a is not definedКрок 2: створюється об'єкт Error
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: припинення виконання, якщо помилку не спіймано
Якщо помилку не спіймано, програма зупиняється:
console.log(a);
console.log("Цей код не виконається");Після ReferenceError у першому рядку виконання переривається, і другий рядок уже не буде виконано.
Крок 5: відновлення роботи і блок finally
Якщо помилку спіймано в try...catch, виконання програми продовжується після блоку catch:
try {
JSON.parse("{ not valid json }");
} catch (error) {
console.log("Сталася помилка:", error.message);
}
console.log("Код продовжується...");Вивід:
Сталася помилка: Expected property name or '}' in JSON at position 2
Код продовжується...Якщо додати блок finally, він виконається завжди, незалежно від того, була помилка чи ні:
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, і викинуту помилку, тому збій просто зникне без сліду. - Вважати, що неспіймана помилка ламає лише один рядок. Вона зупиняє весь поточний стек викликів, тому далі не виконається нічого з цієї гілки коду.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.