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