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

1. `try {...} catch {...}`
2. `try {...} finally {...}`
3. `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`.


```js
try {
  throw "myException"; // создание исключения
} catch (e) {
  // инструкции для обработки ошибок
  logMyErrors(e); // передать объект исключения обработчику ошибок
}
```


Блок `catch` задаёт идентификатор (`e` в примере выше) который содержит объект исключения (в примере выше — значение, переданное оператору `throw`). Область видимости этого объекта ограничивается блоком `catch`.

### Условный блок `catch`

"Условные блоки `catch`" можно создавать, используя `try...catch` с `if...else if...else`, как здесь:


```js
try {
  myroutine(); // может выбрасывать три вида исключений
} catch (e) {
  if (e instanceof TypeError) {
    // обработка исключения TypeError
  } else if (e instanceof RangeError) {
    // обработка исключения RangeError
  } else if (e instanceof EvalError) {
    // обработка исключения EvalError
  } else {
    // обработка остальных исключений
    logMyErrors(e); // передать обработчику ошибок
  }
}
```


Частый сценарий использования — обработать известные исключения, а при неизвестных ошибках, пробросить их дальше:


```js
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`.


```js
try {
  if (!firstValidation()) {
    throw 1;
  }
  if (!secondValidation()) {
    throw 2;
  }
} catch (e) {
  // Выводит 1 или 2 (если не произошло никаких других ошибок)
  console.log(e);
}
```

### Блок finally

Блок `finally` содержит код который будет запущен после кода в блоках `try` и `catch`. Обратите внимание, что код в блоке `finally` запускается в независимости от того, было ли выброшено исключение или нет. Также код в блоке `finally` будет запущен вне зависимости от того, присутствует блок `catch` или нет. Блок `finally` можно использовать для того, чтобы скрипт безопасно завершил работу в случае ошибки. Например, если необходимо освободить память и ресурсы которые использовал скрипт.

Наличие специального блока, связанного с ошибкой, который выполняется вне зависимости от наличия исключительной ситуации, может показаться странным, но эта конструкция на самом деле весьма полезна. Рассмотрим пример кода:


```js
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`:


```js
try {
  window.addEventListener("scroll", expensiveCalculations);
  maybeThrowError();
} catch {
  maybeThrowError();
} finally {
  window.removeEventListener("scroll", expensiveCalculations);
}
```


Другой пример: работа с файлами. В следующем фрагменте кода показывается, как скрипт открывает файл и записывает в него какие-то данные (в серверном окружении JavaScript имеет доступ к файловой системе). Во время записи может произойти ошибка. Но после открытия файл очень важно закрыть, потому что незакрытый файл может привести к утечкам памяти. В таких случаях используется блок `finally`:


```js
openMyFile();
try {
  // Сделать что-то с файлом
  writeMyFile(theData);
} finally {
  closeMyFile(); // Закрыть файл, что бы ни произошло
}
```

Примеры
-------

### Вложенные блоки try

Для начала давайте посмотрим что делает этот код:


```js
try {
  try {
    throw new Error("упс");
  } finally {
    console.log("finally");
  }
} catch (e) {
  console.error("внешний блок catch", e.message);
}

// Вывод:
// "finally"
// "внешний блок catch" "упс"
```


Теперь отловим исключение во внутреннем блоке `try`, добавив к нему блок `catch`:


```js
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"
```


Наконец, пробросим ошибку


```js
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`.


```js
(() => {
  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 with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `Error`
* `throw`