try...catch

Інструкція try...catch (спробувати-перехопити) складається з блока try і або блока catch, або блока finally, або їх обох. Код в блоку try виконується першим, і якщо він викидає виняток, то виконується код у блоку catch. Код у блоку finally виконується в будь-якому випадку, перед тим, як контроль виконання полишає всю конструкцію.

Спробуйте його в дії

Синтаксис

try {
  tryStatements
} catch (exceptionVar) {
  catchStatements
} finally {
  finallyStatements
}
tryStatements

Інструкції до виконання.

catchStatements

Інструкція, що виконується, коли блок try викидає виняток.

exceptionVar Необов'язкове

Необов'язковий ідентифікатор, що містить перехоплений виняток для відповідного блока catch. Якщо блок catch не використовує значення винятку, то можна опустити exceptionVar і дужки біля нього: catch {...}.

finallyStatements

Інструкції, що виконуються перед тим, як контроль виконання виходить з конструкції try...catch...finally. Ці інструкції виконуються незалежно від того, чи був викинутий або перехоплений виняток.

Опис

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

  • try...catch
  • try...finally
  • try...catch...finally

На відміну від інших конструкцій, як то if чи for, блоки try, catch і finally мусять бути блоками, а не одиничними інструкціями.

try doSomething(); // SyntaxError
catch (e) console.log(e);

Блок catch містить інструкції, котрі вказують, що робити, якщо блок try викинув виняток. Якщо будь-яка інструкція всередині блока try (або в функції, викликаної зсередини блока try) викидає виняток, контроль негайно переходить до блока catch. Якщо в блоку try не викидається жодний виняток, то блок catch пропускається.

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

Інструкції try можна вкладати одну в одну. Якщо внутрішня інструкція try не має блока catch, то використовується блок catch зовнішньої try.

Також інструкцію try можна застосовувати для обробки винятків JavaScript. Дивіться Посібник з JavaScript для отримання подробиць щодо винятків JavaScript.

Безумовний блок catch

Коли застосовується блок catch, блок catch виконується, коли зсередини блока try викидається будь-який виняток. Наприклад, коли в наступному коді трапляється виняток, контроль переходить до блоку catch.

try {
  throw "myException"; // породжує виняток
} catch (e) {
  // інструкції для обробки будь-яких винятків
  logMyErrors(e); // передати об'єкт винятку обробнику помилок
}

Блок catch вказує ідентифікатор (e в прикладі вище), котрий зберігає значення винятку; це значення доступне лише в межах області видимості блоку catch.

Умовні блоки catch

"Умовні блоки catch" можна утворити шляхом комбінування блоків try...catch зі структурами if...else if...else, отак:

try {
  myroutine(); // може викинути три типи винятків
} catch (e) {
  if (e instanceof TypeError) {
    // інструкції для обробки винятків TypeError
  } else if (e instanceof RangeError) {
    // інструкції для обробки RangeError
  } else if (e instanceof EvalError) {
    // інструкції для обробки EvalError
  } else {
    // інструкції для обробки будь-яких непередбачених винятків
    logMyErrors(e); // передати об'єкт винятку обробнику помилок
  }
}

Поширена ситуація для застосування такого підходу – потреба перехопити (й заглушити) невелику підмножину очікуваних помилок, а потім повторно викинути помилку, якщо вона до такої підмножини не належить:

try {
  myRoutine();
} catch (e) {
  if (e instanceof RangeError) {
    // інструкції для обробки цієї дуже поширеної очікуваної помилки
  } else {
    throw e; // повторно викинути помилку без змін
  }
}

Ідентифікатор винятку

Коли в блоку try викидається виняток, exception_var (тобто e в catch (e)) зберігає значення винятку. Цей ідентифікатор можна використати для отримання інформації про викинутий виняток. Він доступний лише в області видимості блоку catch. Якщо значення винятку непотрібне, цей ідентифікатор можна опустити.

function isValidJSON(text) {
  try {
    JSON.parse(text);
    return true;
  } catch {
    return false;
  }
}

Блок finally

Блок finally містить інструкції, що будуть виконані після виконання блоку try та блоку (чи блоків) catch, але до інструкцій, що стоять після блоку try...catch...finally. Потік виконання обов'язково зайде до блоку finally, що може відбутися в один з наступних способів:

  • Безпосередньо перед нормальним завершенням виконання блоку try (винятків викинуто не було);
  • Безпосередньо перед нормальним завершенням виконання блоку catch;
  • Безпосередньо перед виконанням інструкції контролю потоку виконання (return, throw, break, continue) в блоку try чи блоку catch.

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

Наступний приклад демонструє одну з ситуацій для використання блоку finally. Код відкриває файл, а потім виконує інструкції, що використовують цей файл; блок finally пересвідчується, що файл обов'язково закривається після використання, навіть якщо було викинуто виняток.

openMyFile();
try {
  // затягти ресурс
  writeMyFile(theData);
} finally {
  closeMyFile(); // завжди закривати ресурс
}

Інструкції контролю потоку виконання (return, throw, break, continue) в блоку finally будуть "приховувати" будь-яке підсумкове значення блоку try чи блоку catch. В прикладі нижче блок try пробує повернути 1, але перед поверненням контроль виконання спершу переходить до блоку finally, тож натомість повертається повернене значення блоку finally.

function doIt() {
  try {
    return 1;
  } finally {
    return 2;
  }
}

doIt(); // повертає 2

Загалом є недоброю ідеєю мати інструкції контролю потоку виконання в блоку finally. Його слід використовувати лише для коду очищення.

Приклади

Вкладені блоки try

По-перше, погляньмо, що станеться з цим:

try {
  try {
    throw new Error("йой");
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("зовнішній", ex.message);
}

// Друкує:
// "finally"
// "зовнішній" "йой"

Тепер – якщо виняток перехоплений уже внутрішнім блоком try: додається блок catch:

try {
  try {
    throw new Error("йой");
  } catch (ex) {
    console.error("внутрішній", ex.message);
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("зовнішній", ex.message);
}

// Друкує:
// "внутрішній" "йой"
// "finally"

А тепер – повторне викидання помилки.

try {
  try {
    throw new Error("йой");
  } catch (ex) {
    console.error("внутрішній", ex.message);
    throw ex;
  } finally {
    console.log("finally");
  }
} catch (ex) {
  console.error("зовнішній", ex.message);
}

// Друкує:
// "внутрішній" "йой"
// "finally"
// "зовнішній" "йой"

Будь-який виняток буде перехоплений лише раз, найближчим блоком catch, котрий його охоплює, якщо цей виняток не викидається повторно. Звісно, будь-які нові винятки, винесені у "внутрішньому" блоку (тому, що код в блоку catch може робити щось, що викидає винятки), будуть перехоплені в "зовнішньому" блоку.

Повернення значення з блоку finally

Якщо блок finally повертає значення, то таке значення стає поверненим значенням всієї інструкції try-catch-finally, незалежно від будь-яких інструкцій return в блоках try і catch. Так само це стосується винятків, викинутих зсередини блоку catch:

(() => {
  try {
    try {
      throw new Error("йой");
    } catch (ex) {
      console.error("внутрішній", ex.message);
      throw ex;
    } finally {
      console.log("finally");
      return;
    }
  } catch (ex) {
    console.error("зовнішній", ex.message);
  }
})();

// Друкує:
// "внутрішній" "йой"
// "finally"

Зовнішній "йой" не викидається у зв'язку з return у блоку finally. Те саме стосується будь-якого значення, поверненого з блоку catch.

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
try...catch
Chrome Full support 1
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support 5
Opera Full support 4
Safari Full support 1
WebView Android Full support 4.4
Chrome Android Full support 18
Firefox for Android Full support 4
Opera Android Full support 10.1
Safari on iOS Full support 1
Samsung Internet Full support 1.0
Deno Full support 1.0
Node.js Full support 0.10.0
Optional catch binding
Chrome Full support 66
Edge Full support 79
Firefox Full support 58
Internet Explorer No support No
Opera Full support 53
Safari Full support 11.1
WebView Android Full support 66
Chrome Android Full support 66
Firefox for Android Full support 58
Opera Android Full support 47
Safari on iOS Full support 11.3
Samsung Internet Full support 9.0
Deno Full support 1.0
Node.js Full support 10.0.0

Дивіться також