--- title: try...catch slug: Web/JavaScript/Reference/Statements/try...catch tags: - JavaScript - Исключение - Ошибка translation_of: Web/JavaScript/Reference/Statements/try...catch ---
Конструкция 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
, он вызывается для любого исключения в блоке 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; // пробросить неизвестные ошибки } }
Обратите внимание: Firefox раньше поддерживал краткую запись условных блоков catch
:
try { myroutine(); // может выбрасывать три вида исключения } catch (e if e instanceof TypeError) { // обработка исключений TypeError } catch (e if e instanceof RangeError) { // обработка исключений RangeError } catch (e if e instanceof EvalError) { // обработка исключений EvalError } catch (e) { // обработка остальных исключения logMyErrors(e); }
Однако, такой синтаксис никогда не был частью спецификации ECMAScript и был удалён из Firefox после версии 59. Сейчас он не поддерживается ни в одном браузере.
Когда в блоке try
выбрасывается исключение, exception_var
(т. е. e
в конструкции catch (e)
) содержит значение исключения. Его можно использовать, чтобы получить больше информации об выброшенном исключении. Идентификатор доступен только в области видимости блока catch
.
try { if (!firstValidation()) { throw 1; } if (!secondValidation()) { throw 2; } } catch (e) { // Выводит 1 или 2 (если не произошло никаких других ошибок) console.log(e); }
Блок 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 { 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
возвращает какое-либо значение, оно становится значением, которое возвращает вся конструкция try...catch...finally
, вне зависимости от любых инструкций return
в блоках try
и catch
. Также игнорируются исключения, выброшенные блоком catch
.
try { try { throw new Error('упс'); } catch (e) { console.error('внутренний блок catch', e.message); throw e; } finally { console.log('finally'); return; } } catch (e) { console.error('внешний блок catch', e.message); } // Output: // "внутренний блок catch" "упс" // "finally"
"упс" не доходит до внешнего блока из-за инструкции return
в блоке finally
. То же самое произойдёт с любым значением, возвращаемым из блока catch
.
Спецификация | Состояние | Примечание |
---|---|---|
{{SpecName('ES3')}} | {{Spec2('ES3')}} | Изначальная редакция. Реализовано в JavaScript 1.4 |
{{SpecName('ES5.1', '#sec-12.14', 'try statement')}} | {{Spec2('ES5.1')}} | |
{{SpecName('ES6', '#sec-try-statement', 'try statement')}} | {{Spec2('ES6')}} | |
{{SpecName('ESDraft', '#sec-try-statement', 'try statement')}} | {{Spec2('ESDraft')}} | Not part of the current ECMA-262 standard: Multiple catch clauses and conditional clauses (SpiderMonkey extension, JavaScript 1.5). |
{{CompatibilityTable}}
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Basic support | {{CompatVersionUnknown}} | {{CompatGeckoDesktop("6")}} | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} |
Conditional clauses (non-standard) |
{{CompatNo}} | {{CompatVersionUnknown}} | {{CompatNo}} | {{CompatNo}} | {{CompatNo}} |
Feature | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|
Basic support | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} | {{CompatVersionUnknown}} |
Conditional clauses (non-standard) |
{{CompatNo}} | {{CompatNo}} | {{CompatVersionUnknown}} | {{CompatNo}} | {{CompatNo}} | {{CompatNo}} |