aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/statements/try...catch/index.html
blob: 70766c3f48f32df0ef6acea5c7a5c2cdf890e7ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
---
title: try...catch
slug: Web/JavaScript/Reference/Statements/try...catch
tags:
  - JavaScript
  - Исключение
  - Ошибка
translation_of: Web/JavaScript/Reference/Statements/try...catch
---
<div>{{jsSidebar("Statements")}}</div>

<p>Конструкция <code>try...catch</code> пытается выполнить инструкции в блоке <code>try</code>, и, в случае ошибки, выполняет блок <code>catch</code>.</p>

<h2 id="Синтаксис">Синтаксис</h2>

<pre class="syntaxbox">try {
   <em>try_statements</em>
}
[catch (<em>exception_var_1</em> if <em>condition_1</em>) { // не стандартно
   <em>catch_statements_1</em>
}]
...
[catch (<em>exception_var_2</em>) {
   <em>catch_statements_2</em>
}]
[finally {
   <em>finally_statements</em>
}]
</pre>

<dl>
 <dt><code>try_statements</code></dt>
 <dd>Инструкции для выполнения.</dd>
</dl>

<dl>
 <dt><code>catch_statements_1</code>, <code>catch_statements_2</code></dt>
 <dd>
 <p>Инструкции, которые будут выполнены, если произойдёт ошибка в блоке <code><font face="Consolas, Liberation Mono, Courier, monospace">try</font></code>.</p>
 </dd>
</dl>

<dl>
 <dt><code>exception_var_1</code>, <code>exception_var_2</code></dt>
 <dd>Идентификатор для хранения объекта ошибки, который впоследствии используется в блоке <code>catch</code></dd>
</dl>

<dl>
 <dt><code>condition_1</code></dt>
 <dd>Условное выражение.</dd>
</dl>

<dl>
 <dt><code>finally_statements</code></dt>
 <dd>Инструкции, которые выполняются после завершения блока <code>try</code>. Выполнение происходит в независимости от того, произошла ошибка или нет.</dd>
</dl>

<h2 id="Описание">Описание</h2>

<p>Конструкция <code>try</code> содержит блок <code>try</code>, в котором находится одна или несколько инструкций (Блок (<code>{}</code> ) обязательно должен присутствовать, даже если выполняется всего одна инструкция), и хотя бы один блок <code>catch</code> или <code>finally</code>. Таким образом, есть три основные формы конструкции <code>try</code>:</p>

<ol>
 <li><code>try {...} catch {...}</code></li>
 <li><code>try {...} finally {...}</code></li>
 <li><code>try {...} catch {...} finally {...}</code></li>
</ol>

<p>Блок <code>catch</code> содержит инструкции, которые будут выполнены, если в блоке <code>try</code> произошла ошибка. Если любая инструкция в блоке <code>try</code> выбрасывает исключение, то управление сразу же переходит в блок <code>catch</code>. Если в блок <code>try</code> не было выброшено исключение, то блок <code>catch</code> не выполняется.</p>

<p>Блок <code>finally</code> выполнится после выполнения блоков <code>try</code> и <code>catch</code>, но перед инструкциями, следующими за конструкцией <code>try...catch</code>. Он выполняется всегда, в независимости от того, было исключение или нет.</p>

<p>Вы можете использовать вложенные конструкции <code>try</code>. Если внутренняя конструкция <code>try</code> не имеет блока <code>catch</code> (такое может быть при её использовании в виде <code>try {...} finaly {...}</code>, потому что <code>try {...}</code> не может быть без блоков <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">catch</span></font> или <code>finally</code>), будет вызван <code>сatch</code> внешней конструкции <code>try</code>.</p>

<p>Конструкция <code>try</code> также используется для обработки исключений JavaScript (то есть, выброшенных внутренними функциями языка или парсером). Загляните в <a href="/ru-RU/docs/Web/JavaScript/Guide">JavaScript руководство</a> для дополнительной информации о JavaScript исключениях.</p>

<h3 id="Безусловный_блок_catch">Безусловный блок catch</h3>

<p>При использовании блока <code>catch</code>, он вызывается для любого исключения в блоке <code>try</code>. Например, когда в следующем коде происходит ошибка, управление переходит к блоку <code>catch</code>.</p>

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

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

<h3 id="Условный_блок_catch">Условный блок <code>catch</code></h3>

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

<pre class="brush: 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); // передать обработчику ошибок
  }
}</pre>

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

<pre class="brush: js">try {
  myRoutine();
} catch(e) {
  if (e instanceof RangeError) {
    // обработка известного исключения, с которым
    // понятно, что делать
  } else {
    throw e; // пробросить неизвестные ошибки
  }
}
</pre>

<div class="blockIndicator note">
<p><strong>Обратите внимание</strong>: Firefox раньше поддерживал краткую запись условных блоков <code>catch</code>:</p>

<pre>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);
}
</pre>

<p>Однако, такой синтаксис никогда не был частью спецификации ECMAScript и был удалён из Firefox после версии 59. Сейчас он не поддерживается ни в одном браузере.</p>
</div>

<h3 id="Идентификатор_исключения">Идентификатор исключения</h3>

<p>Когда в блоке <code>try</code> выбрасывается исключение, <code>exception_var</code> (т. е. <code>e</code> в конструкции <code>catch (e)</code>) содержит значение исключения. Его можно использовать, чтобы получить больше информации об выброшенном исключении. Идентификатор доступен только в <a href="https://wiki.developer.mozilla.org/docs/Glossary/Scope">области видимости</a> блока <code>catch</code>.</p>

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

<h3 id="Блок_finally">Блок finally</h3>

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

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

<pre class="brush: js">function expensiveCalculations() {
  // Сложные вычисления
}

function maybeThrowError() {
  // Функция, которая может выбросить исключение
  if(Math.random() &gt; 0.5) throw new Error()
}

try {
  // Теперь при прокрутке страницы будут происходить
  // сложные вычисления, что сильно скажется на
  // производительности
  window.addEventListener('scroll', expensiveCalculations)
  maybeThrowError()
} catch {
  // Если функция maybeThrowError выбросит исключения,
  // управление сразу перейдёт в блок catch и
  // сложные вычисления продолжат выполняться до
  // перезагрузки страницы
  maybeThrowError()
}
window.removeEventListener('scroll', expensiveCalculations)</pre>

<p>В этом примере, если функция <code>maybeThrowError</code> выбросит исключение внутри блока <code>try</code>, управление перейдёт в блок <code>catch</code>. Если и в блоке <code>catch</code> эта функция тоже выбросит исключение, то выполнение кода прервётся, и обработчик события не будет снят, пока пользователь не перезагрузит страницу, что плохо скажется на скорости работы. Для того, чтобы избежать таких ситуаций, следует использовать блок <code>finally</code>:</p>

<pre class="brush: js">try {
  window.addEventListener('scroll', expensiveCalculations)
  maybeThrowError()
} catch {
  maybeThrowError()
} finally {
  window.removeEventListener('scroll', expensiveCalculations)
}

</pre>

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

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

<h2 id="Примеры">Примеры</h2>

<h3 id="Вложенные_блоки_try">Вложенные блоки try</h3>

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

<pre class="brush: js">try {
  try {
    throw new Error('упс');
  }
  finally {
    console.log('finally');
  }
}
catch (e) {
  console.error('внешний блок catch', e.message);
}

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

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

<pre class="brush: 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"
</pre>

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

<pre class="brush: 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"
</pre>

<p>Любое исключение будет передано только в ближайший блок <code>catch</code>, если он не пробросит его дальше. Все исключения, выброшенными внутренними блоками (потому что код в блоке <code>catch</code> также может выбросить исключение), будут пойманы внешними.</p>

<h3 id="Возвращение_значения_из_блока_finally">Возвращение значения из блока finally</h3>

<p>Если блок <code>finally</code> возвращает какое-либо значение, оно становится значением, которое возвращает вся конструкция <code>try...catch...finally</code>, вне зависимости от любых инструкций <code>return</code> в блоках <code>try</code> и <code>catch</code>. Также игнорируются исключения, выброшенные блоком <code>catch</code>.</p>

<pre class="brush: js">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"
</pre>

<p>"упс" не доходит до внешнего блока из-за инструкции <code>return</code> в блоке <code>finally</code>. То же самое произойдёт с любым значением, возвращаемым из блока <code>catch</code>.</p>

<h2 id="Спецификации">Спецификации</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Спецификация</th>
   <th scope="col">Состояние</th>
   <th scope="col">Примечание</th>
  </tr>
  <tr>
   <td>{{SpecName('ES3')}}</td>
   <td>{{Spec2('ES3')}}</td>
   <td>Изначальная редакция. Реализовано в JavaScript 1.4</td>
  </tr>
  <tr>
   <td>{{SpecName('ES5.1', '#sec-12.14', 'try statement')}}</td>
   <td>{{Spec2('ES5.1')}}</td>
   <td></td>
  </tr>
  <tr>
   <td>{{SpecName('ES6', '#sec-try-statement', 'try statement')}}</td>
   <td>{{Spec2('ES6')}}</td>
   <td></td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-try-statement', 'try statement')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td>Not part of the current ECMA-262 standard: Multiple catch clauses and conditional clauses (SpiderMonkey extension, JavaScript 1.5).</td>
  </tr>
 </tbody>
</table>

<h2 id="Совместимость">Совместимость</h2>

<p>{{CompatibilityTable}}</p>

<div id="compat-desktop">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Chrome</th>
   <th>Firefox (Gecko)</th>
   <th>Internet Explorer</th>
   <th>Opera</th>
   <th>Safari</th>
  </tr>
  <tr>
   <td>Basic support</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatGeckoDesktop("6")}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
  </tr>
  <tr>
   <td>Conditional clauses<br>
    (non-standard)</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
  </tr>
 </tbody>
</table>
</div>

<div id="compat-mobile">
<table class="compat-table">
 <tbody>
  <tr>
   <th>Feature</th>
   <th>Android</th>
   <th>Chrome for Android</th>
   <th>Firefox Mobile (Gecko)</th>
   <th>IE Mobile</th>
   <th>Opera Mobile</th>
   <th>Safari Mobile</th>
  </tr>
  <tr>
   <td>Basic support</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatVersionUnknown}}</td>
  </tr>
  <tr>
   <td>Conditional clauses<br>
    (non-standard)</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatVersionUnknown}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
   <td>{{CompatNo}}</td>
  </tr>
 </tbody>
</table>
</div>

<h2 id="См._также">См. также</h2>

<ul>
 <li>{{jsxref("Error")}}</li>
 <li>{{jsxref("Statements/throw", "throw")}}</li>
</ul>