try...catch
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Конструкция try...catch
пытается выполнить инструкции в блоке try
, и, в случае ошибки, выполняет блок catch
.
Синтаксис
try { try_statements } [catch (exception_var_1 if condition_1) { // не стандартно catch_statements_1 }] ... [catch (exception_var_2) { catch_statements_2 }] [finally { finally_statements }]
try_statements
-
Инструкции для выполнения.
catch_statements_1
,catch_statements_2
-
Инструкции, которые будут выполнены, если произойдёт ошибка в блоке
try
. exception_var_1
,exception_var_2
-
Идентификатор для хранения объекта ошибки, который впоследствии используется в блоке
catch
condition_1
-
Условное выражение.
finally_statements
-
Инструкции, которые выполняются после завершения блока
try
. Выполнение происходит в независимости от того, произошла ошибка или нет.
Описание
Конструкция try
содержит блок try
, в котором находится одна или несколько инструкций (Блок ({}
) обязательно должен присутствовать, даже если выполняется всего одна инструкция), и хотя бы один блок catch
или finally
. Таким образом, есть три основные формы конструкции try
:
try {...} catch {...}
try {...} finally {...}
try {...} catch {...} finally {...}
Блок catch
содержит инструкции, которые будут выполнены, если в блоке try
произошла ошибка. Если любая инструкция в блоке try
выбрасывает исключение, то управление сразу же переходит в блок catch
. Если в блок try
не было выброшено исключение, то блок catch
не выполняется.
Блок finally
выполнится после выполнения блоков try
и catch
, но перед инструкциями, следующими за конструкцией try...catch
. Он выполняется всегда, в независимости от того, было исключение или нет.
Вы можете использовать вложенные конструкции try
. Если внутренняя конструкция try
не имеет блока catch
(такое может быть при её использовании в виде try {...} finaly {...}
, потому что try {...}
не может быть без блоков catch или finally
), будет вызван сatch
внешней конструкции try
.
Конструкция try
также используется для обработки исключений JavaScript (то есть, выброшенных внутренними функциями языка или парсером). Загляните в JavaScript руководство для дополнительной информации о JavaScript исключениях.
Безусловный блок catch
При использовании блока catch
, он вызывается для любого исключения в блоке try
. Например, когда в следующем коде происходит ошибка, управление переходит к блоку catch
.
try {
throw "myException"; // создание исключения
} catch (e) {
// инструкции для обработки ошибок
logMyErrors(e); // передать объект исключения обработчику ошибок
}
Блок catch
задаёт идентификатор (e
в примере выше) который содержит объект исключения (в примере выше — значение, переданное оператору throw
). Область видимости этого объекта ограничивается блоком 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
.
try {
if (!firstValidation()) {
throw 1;
}
if (!secondValidation()) {
throw 2;
}
} catch (e) {
// Выводит 1 или 2 (если не произошло никаких других ошибок)
console.log(e);
}
Блок finally
Блок finally
содержит код который будет запущен после кода в блоках try
и catch
. Обратите внимание, что код в блоке finally
запускается в независимости от того, было ли выброшено исключение или нет. Также код в блоке finally
будет запущен вне зависимости от того, присутствует блок catch
или нет. Блок finally
можно использовать для того, чтобы скрипт безопасно завершил работу в случае ошибки. Например, если необходимо освободить память и ресурсы которые использовал скрипт.
Наличие специального блока, связанного с ошибкой, который выполняется вне зависимости от наличия исключительной ситуации, может показаться странным, но эта конструкция на самом деле весьма полезна. Рассмотрим пример кода:
function expensiveCalculations() {
// Сложные вычисления
}
function maybeThrowError() {
// Функция, которая может выбросить исключение
if (Math.random() > 0.5) throw new Error();
}
try {
// Теперь при прокрутке страницы будут происходить
// сложные вычисления, что сильно скажется на
// производительности
window.addEventListener("scroll", expensiveCalculations);
maybeThrowError();
} catch {
// Если функция maybeThrowError выбросит исключения,
// управление сразу перейдёт в блок catch и
// сложные вычисления продолжат выполняться до
// перезагрузки страницы
maybeThrowError();
}
window.removeEventListener("scroll", expensiveCalculations);
В этом примере, если функция maybeThrowError
выбросит исключение внутри блока try
, управление перейдёт в блок catch
. Если и в блоке catch
эта функция тоже выбросит исключение, то выполнение кода прервётся, и обработчик события не будет снят, пока пользователь не перезагрузит страницу, что плохо скажется на скорости работы. Для того, чтобы избежать таких ситуаций, следует использовать блок finally
:
try {
window.addEventListener("scroll", expensiveCalculations);
maybeThrowError();
} catch {
maybeThrowError();
} finally {
window.removeEventListener("scroll", expensiveCalculations);
}
Другой пример: работа с файлами. В следующем фрагменте кода показывается, как скрипт открывает файл и записывает в него какие-то данные (в серверном окружении JavaScript имеет доступ к файловой системе). Во время записи может произойти ошибка. Но после открытия файл очень важно закрыть, потому что незакрытый файл может привести к утечкам памяти. В таких случаях используется блок finally
:
openMyFile();
try {
// Сделать что-то с файлом
writeMyFile(theData);
} finally {
closeMyFile(); // Закрыть файл, что бы ни произошло
}
Примеры
Вложенные блоки try
Для начала давайте посмотрим что делает этот код:
try {
try {
throw new Error("упс");
} finally {
console.log("finally");
}
} catch (e) {
console.error("внешний блок catch", e.message);
}
// Вывод:
// "finally"
// "внешний блок catch" "упс"
Теперь отловим исключение во внутреннем блоке try
, добавив к нему блок catch
:
try {
try {
throw new Error("упс");
} catch (e) {
console.error("внутренний блок catch", e.message);
} finally {
console.log("finally");
}
} catch (e) {
console.error("внешний блок catch", e.message);
}
// Output:
// "внутренний блок catch" "упс"
// "finally"
Наконец, пробросим ошибку
try {
try {
throw new Error("упс");
} catch (e) {
console.error("внутренний блок catch", e.message);
throw e;
} finally {
console.log("finally");
}
} catch (e) {
console.error("внешний блок catch", e.message);
}
// Вывод:
// "внутренний блок catch" "oops"
// "finally"
// "внешний блок catch" "oops"
Любое исключение будет передано только в ближайший блок catch
, если он не пробросит его дальше. Все исключения, выброшенными внутренними блоками (потому что код в блоке catch
также может выбросить исключение), будут пойманы внешними.
Возвращение значения из блока finally
Если блок finally
возвращает какое-либо значение, оно становится значением, которое возвращает вся конструкция try...catch...finally
, вне зависимости от любых инструкций return
в блоках try
и catch
. Также игнорируются исключения, выброшенные блоком catch
.
(() => {
try {
try {
throw new Error("oops");
} catch (ex) {
console.error("inner", ex.message);
throw ex;
} finally {
console.log("finally");
return;
}
} catch (ex) {
console.error("outer", ex.message);
}
})();
// Logs:
// "inner" "oops"
// "finally"
"упс" не доходит до внешнего блока из-за инструкции return
в блоке finally
. То же самое произойдёт с любым значением, возвращаемым из блока catch
.
Спецификации
Specification |
---|
ECMAScript Language Specification # sec-try-statement |
Совместимость с браузерами
BCD tables only load in the browser