9 березня 2025 р.

Робота з помилками, "try...catch"

Якими чудовими програмістами ми б не були, часом трапляється, що в наших скриптах виникають помилки. Вони можуть виникнути через нашу неуважність, непередбачувані вхідні дані від користувачів, неправильні відповіді від сервера або з тисяч інших причин.

Якщо виникають помилки, то скрипти, зазвичай, “помирають” (раптово припиняють роботу) та виводять інформацію про помилку в консоль.

Але існує синтаксична конструкція try...catch, що дозволяє нам “перехоплювати” помилки, що дає змогу скриптам виконати потрібні дії, а не раптово припинити роботу.

Синтаксис “try…catch”

Конструкція try...catch містить два головних блоки: try, а потім catch:

try {

  // код...

} catch (err) {

  // код обробки помилки

}

Це працює наступним чином:

  1. В першу чергу виконується код в блоці try {...}.
  2. Якщо не виникає помилок, то блок catch (err) ігнорується: виконання досягає кінця блоку try та продовжується поза блоком catch.
  3. Якщо виникає помилка, тоді виконання в try припиняється і виконання коду продовжується з початку блоку catch (err). Змінна err (можна обрати будь-яке ім’я) буде містити об’єкт помилки з додатковою інформацією.

Отже, помилка всередині блоку try {...} не призводить до раптового припинення роботи скрипту – ми отримуємо можливість обробити її в catch.

Подивімося на декілька прикладів.

  • Приклад без винятка: виводить alert (1) та (2):

    try {
    
      alert('Початок блоку try');  // (1) <--
    
      // ...код без помилок
    
      alert('Кінець блоку try');   // (2) <--
    
    } catch (err) {
    
      alert('Помилок немає, тому catch ігнорується'); // (3)
    
    }
  • Приклад з помилкою: винятком (1) та (3):

    try {
    
      alert('Початок блоку try');  // (1) <--
    
      lalala; // помилка, variable is not defined!
    
      alert('Кінець блоку try (не буде виконано)');  // (2)
    
    } catch (err) {
    
      alert(`Виникла помилка!`); // (3) <--
    
    }
try...catch працює тільки з винятками, що виникають під час виконання скрипту

Щоб блок try...catch спрацював, код повинен запускатися. Іншими словами, це повинен бути валідний JavaScript код.

Це не спрацює, якщо код містить синтаксичні помилки, як-от незакриті фігурні дужки:

try {
  {{{{{{{{{{{{
} catch (err) {
  alert("Це не валідний код, рушій його не зрозуміє");
}

JavaScript рушій спочатку прочитує код і тільки потім виконує його. Помилки, що виникають у фазі читання називаються “помилки парсингу”, вони не можуть бути обробленими і скрипти припиняють свою роботу. Це виникає через те, що рушій не може зрозуміти код.

Тому try...catch може тільки обробляти помилки, що виникають у правильному коді. Такі помилки називають “помилками під час виконання” (runtime errors) або “винятками” (exceptions).

Нюанс перекладу

В українській мові відсутній точний відповідник англійського слова “exception”. Слово “виняток” для україномовної людини здається не таким зручним і зрозумілим як слово “помилка”. І тим не менш, слово помилка вживають по відношенню до всіх помилок. А для окремого підвиду помилок, конкретно для помилок, що стаються під час виконання коду, іноді використовують слово виняток. Тому коли нижче бачитимете слово “виняток”, просто знайте, що мова йде про помилку.

try...catch працює синхронно

Якщо виняток трапляється у “запланованому до виконання” коді, як от в setTimeout, тоді try...catch не зможе перехопити помилку:

try {
  setTimeout(function() {
    noSuchVariable; // скрипт припинить свою роботу
  }, 1000);
} catch (err) {
  alert( "не спрацює" );
}

Це відбувається через те, що функція буде виконана пізніше, коли рушій вже вийде з блоку try...catch.

Щоб перехопити виняток всередині функції запланованої до виконання, try...catch повинен бути всередині тієї функції:

setTimeout(function() {
  try {
    noSuchVariable; // try...catch опрацює помилку!
  } catch {
    alert( "помилку перехоплено тут!" );
  }
}, 1000);