|
1 | 1 |
|
2 |
| -# Error handling with promises |
| 2 | +# Ošetřování chyb pomocí příslibů |
3 | 3 |
|
4 |
| -Promise chains are great at error handling. When a promise rejects, the control jumps to the closest rejection handler. That's very convenient in practice. |
| 4 | +Řetězy příslibů jsou vynikající při ošetřování chyb. Když je příslib zamítnut, řízení skočí do nejbližšího handleru pro zamítnutí. To je v praxi velice užitečné. |
5 | 5 |
|
6 |
| -For instance, in the code below the URL to `fetch` is wrong (no such site) and `.catch` handles the error: |
| 6 | +Například v následujícím kódu je URL předané funkci `fetch` vadné (taková stránka neexistuje) a `.catch` ošetří chybu: |
7 | 7 |
|
8 | 8 | ```js run
|
9 | 9 | *!*
|
10 |
| -fetch('https://no-such-server.blabla') // rejects |
| 10 | +fetch('https://takovy-server-neni.blabla') // zamítne |
11 | 11 | */!*
|
12 |
| - .then(response => response.json()) |
13 |
| - .catch(err => alert(err)) // TypeError: failed to fetch (the text may vary) |
| 12 | + .then(odpověď => odpověď.json()) |
| 13 | + .catch(chyba => alert(chyba)) // TypeError: failed to fetch (text se může lišit) |
14 | 14 | ```
|
15 | 15 |
|
16 |
| -As you can see, the `.catch` doesn't have to be immediate. It may appear after one or maybe several `.then`. |
| 16 | +Jak vidíte, `.catch` nemusí být uvedeno okamžitě. Může se objevit až za jednou nebo i několika funkcemi `.then`. |
17 | 17 |
|
18 |
| -Or, maybe, everything is all right with the site, but the response is not valid JSON. The easiest way to catch all errors is to append `.catch` to the end of chain: |
| 18 | +Nebo možná je se stránkou všechno v pořádku, ale odpověď není platný JSON. Nejjednodušší způsob, jak zachytit všechny chyby, je přidat `.catch` na konec řetězu: |
19 | 19 |
|
20 | 20 | ```js run
|
21 | 21 | fetch('/article/promise-chaining/user.json')
|
22 |
| - .then(response => response.json()) |
23 |
| - .then(user => fetch(`https://api.github.com/users/${user.name}`)) |
24 |
| - .then(response => response.json()) |
25 |
| - .then(githubUser => new Promise((resolve, reject) => { |
26 |
| - let img = document.createElement('img'); |
27 |
| - img.src = githubUser.avatar_url; |
28 |
| - img.className = "promise-avatar-example"; |
29 |
| - document.body.append(img); |
| 22 | + .then(odpověď => odpověď.json()) |
| 23 | + .then(uživatel => fetch(`https://api.github.com/users/${uživatel.name}`)) |
| 24 | + .then(odpověď => odpověď.json()) |
| 25 | + .then(uživatelGitHubu => new Promise((resolve, reject) => { |
| 26 | + let obrázek = document.createElement('img'); |
| 27 | + obrázek.src = uživatelGitHubu.avatar_url; |
| 28 | + obrázek.className = "promise-avatar-example"; |
| 29 | + document.body.append(obrázek); |
30 | 30 |
|
31 | 31 | setTimeout(() => {
|
32 |
| - img.remove(); |
33 |
| - resolve(githubUser); |
| 32 | + obrázek.remove(); |
| 33 | + resolve(uživatelGitHubu); |
34 | 34 | }, 3000);
|
35 | 35 | }))
|
36 | 36 | *!*
|
37 |
| - .catch(error => alert(error.message)); |
| 37 | + .catch(chyba => alert(chyba.message)); |
38 | 38 | */!*
|
39 | 39 | ```
|
40 | 40 |
|
41 |
| -Normally, such `.catch` doesn't trigger at all. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it. |
| 41 | +Za normálních okolností se takové `.catch` vůbec nespustí. Jestliže však je kterýkoli z uvedených příslibů zamítnut (ať už kvůli síťové chybě, vadnému JSONu nebo čemukoli jinému), pak to zachytí. |
42 | 42 |
|
43 |
| -## Implicit try..catch |
| 43 | +## Implicitní try..catch |
44 | 44 |
|
45 |
| -The code of a promise executor and promise handlers has an "invisible `try..catch`" around it. If an exception happens, it gets caught and treated as a rejection. |
| 45 | +Kód příslibového exekutoru a příslibových handlerů má kolem sebe „neviditelné `try..catch`“. Jestliže nastane výjimka, bude zachycena a bude s ní zacházeno jako se zamítnutím. |
46 | 46 |
|
47 |
| -For instance, this code: |
| 47 | +Například tento kód: |
48 | 48 |
|
49 | 49 | ```js run
|
50 |
| -new Promise((resolve, reject) => { |
| 50 | +new Promise((splň, zamítni) => { |
51 | 51 | *!*
|
52 |
| - throw new Error("Whoops!"); |
| 52 | + throw new Error("Ouha!"); |
53 | 53 | */!*
|
54 |
| -}).catch(alert); // Error: Whoops! |
| 54 | +}).catch(alert); // Error: Ouha! |
55 | 55 | ```
|
56 | 56 |
|
57 |
| -...Works exactly the same as this: |
| 57 | +...Funguje přesně stejně jako tento kód: |
58 | 58 |
|
59 | 59 | ```js run
|
60 |
| -new Promise((resolve, reject) => { |
| 60 | +new Promise((splň, zamítni) => { |
61 | 61 | *!*
|
62 |
| - reject(new Error("Whoops!")); |
| 62 | + zamítni(new Error("Ouha!")); |
63 | 63 | */!*
|
64 |
| -}).catch(alert); // Error: Whoops! |
| 64 | +}).catch(alert); // Error: Ouha! |
65 | 65 | ```
|
66 | 66 |
|
67 |
| -The "invisible `try..catch`" around the executor automatically catches the error and turns it into rejected promise. |
| 67 | +„Neviditelné `try..catch`“ okolo exekutoru automaticky zachytí chybu a promění ji v zamítnutý příslib. |
68 | 68 |
|
69 |
| -This happens not only in the executor function, but in its handlers as well. If we `throw` inside a `.then` handler, that means a rejected promise, so the control jumps to the nearest error handler. |
| 69 | +Děje se to nejen ve funkci exekutoru, ale i v jejích handlerech. Jestliže zavoláme `throw` uvnitř handleru `.then`, znamená to zamítnutý příslib, takže řízení skočí do nejbližšího chybového handleru. |
70 | 70 |
|
71 |
| -Here's an example: |
| 71 | +Následuje příklad: |
72 | 72 |
|
73 | 73 | ```js run
|
74 |
| -new Promise((resolve, reject) => { |
75 |
| - resolve("ok"); |
76 |
| -}).then((result) => { |
| 74 | +new Promise((splň, zamítni) => { |
| 75 | + splň("ok"); |
| 76 | +}).then((výsledek) => { |
77 | 77 | *!*
|
78 |
| - throw new Error("Whoops!"); // rejects the promise |
| 78 | + throw new Error("Ouha!"); // zamítne příslib |
79 | 79 | */!*
|
80 |
| -}).catch(alert); // Error: Whoops! |
| 80 | +}).catch(alert); // Error: Ouha! |
81 | 81 | ```
|
82 | 82 |
|
83 |
| -This happens for all errors, not just those caused by the `throw` statement. For example, a programming error: |
| 83 | +To se děje pro všechny chyby, nejen pro ty, které vyvolal příkaz `throw`. Například pro programátorskou chybu: |
84 | 84 |
|
85 | 85 | ```js run
|
86 |
| -new Promise((resolve, reject) => { |
87 |
| - resolve("ok"); |
88 |
| -}).then((result) => { |
| 86 | +new Promise((splň, zamítni) => { |
| 87 | + splň("ok"); |
| 88 | +}).then((výsledek) => { |
89 | 89 | *!*
|
90 |
| - blabla(); // no such function |
| 90 | + blabla(); // taková funkce není |
91 | 91 | */!*
|
92 |
| -}).catch(alert); // ReferenceError: blabla is not defined |
| 92 | +}).catch(alert); // ReferenceError: blabla není definována |
93 | 93 | ```
|
94 | 94 |
|
95 |
| -The final `.catch` not only catches explicit rejections, but also accidental errors in the handlers above. |
| 95 | +Poslední `.catch` zachytává nejen výslovné zamítnutí, ale také neúmyslné chyby v uvedených handlerech. |
96 | 96 |
|
97 |
| -## Rethrowing |
| 97 | +## Opětovné vyvolání |
98 | 98 |
|
99 |
| -As we already noticed, `.catch` at the end of the chain is similar to `try..catch`. We may have as many `.then` handlers as we want, and then use a single `.catch` at the end to handle errors in all of them. |
| 99 | +Jak jsme se již zmínili, `.catch` na konci řetězu se podobá `try..catch`. Můžeme mít tolik handlerů `.then`, kolik chceme, a pak na konci použít jediný `.catch`, aby ošetřil chyby v nich všech. |
100 | 100 |
|
101 |
| -In a regular `try..catch` we can analyze the error and maybe rethrow it if it can't be handled. The same thing is possible for promises. |
| 101 | +V běžném `try..catch` můžeme chybu analyzovat a případně ji opětovně vyvolat, pokud ji nemůžeme ošetřit. Totéž je možné i u příslibů. |
102 | 102 |
|
103 |
| -If we `throw` inside `.catch`, then the control goes to the next closest error handler. And if we handle the error and finish normally, then it continues to the next closest successful `.then` handler. |
| 103 | +Jestliže zavoláme `throw` uvnitř `.catch`, pak řízení přejde do nejbližšího dalšího chybového handleru. A jestliže ošetříme chybu a normálně skončíme, pak bude pokračovat do nejbližšího dalšího úspěšného handleru `.then`. |
104 | 104 |
|
105 |
| -In the example below the `.catch` successfully handles the error: |
| 105 | +V následujícím příkladu `.catch` úspěšně ošetří chybu: |
106 | 106 |
|
107 | 107 | ```js run
|
108 |
| -// the execution: catch -> then |
109 |
| -new Promise((resolve, reject) => { |
| 108 | +// výkon: catch -> then |
| 109 | +new Promise((splň, zamítni) => { |
110 | 110 |
|
111 |
| - throw new Error("Whoops!"); |
| 111 | + throw new Error("Ouha!"); |
112 | 112 |
|
113 |
| -}).catch(function(error) { |
| 113 | +}).catch(function(chyba) { |
114 | 114 |
|
115 |
| - alert("The error is handled, continue normally"); |
| 115 | + alert("Chyba je ošetřena, pokračuje se normálně"); |
116 | 116 |
|
117 |
| -}).then(() => alert("Next successful handler runs")); |
| 117 | +}).then(() => alert("Další úspěšný handler se spustil")); |
118 | 118 | ```
|
119 | 119 |
|
120 |
| -Here the `.catch` block finishes normally. So the next successful `.then` handler is called. |
| 120 | +Zde blok `.catch` normálně skončí. Je tedy vyvolán další úspěšný handler `.then`. |
121 | 121 |
|
122 |
| -In the example below we see the other situation with `.catch`. The handler `(*)` catches the error and just can't handle it (e.g. it only knows how to handle `URIError`), so it throws it again: |
| 122 | +V následujícím příkladu vidíme s `.catch` opačnou situaci. Handler `(*)` zachytí chybu a nemůže ji ošetřit (např. proto, že umí ošetřit jenom `URIError`), takže ji opětovně vyvolá: |
123 | 123 |
|
124 | 124 | ```js run
|
125 |
| -// the execution: catch -> catch |
126 |
| -new Promise((resolve, reject) => { |
| 125 | +// výkon: catch -> catch |
| 126 | +new Promise((splň, zamítni) => { |
127 | 127 |
|
128 |
| - throw new Error("Whoops!"); |
| 128 | + throw new Error("Ouha!"); |
129 | 129 |
|
130 |
| -}).catch(function(error) { // (*) |
| 130 | +}).catch(function(chyba) { // (*) |
131 | 131 |
|
132 |
| - if (error instanceof URIError) { |
133 |
| - // handle it |
| 132 | + if (chyba instanceof URIError) { |
| 133 | + // ošetří ji |
134 | 134 | } else {
|
135 |
| - alert("Can't handle such error"); |
| 135 | + alert("Tuto chybu nemohu ošetřit"); |
136 | 136 |
|
137 | 137 | *!*
|
138 |
| - throw error; // throwing this or another error jumps to the next catch |
| 138 | + throw chyba; // vyvolání této nebo jiné chyby skočí do dalšího catch |
139 | 139 | */!*
|
140 | 140 | }
|
141 | 141 |
|
142 | 142 | }).then(function() {
|
143 |
| - /* doesn't run here */ |
144 |
| -}).catch(error => { // (**) |
| 143 | + /* toto se nespustí */ |
| 144 | +}).catch(chyba => { // (**) |
145 | 145 |
|
146 |
| - alert(`The unknown error has occurred: ${error}`); |
147 |
| - // don't return anything => execution goes the normal way |
| 146 | + alert(`Nastala neznámá chyba: ${chyba}`); |
| 147 | + // nic nevrací => běh pokračuje obvyklým způsobem |
148 | 148 |
|
149 | 149 | });
|
150 | 150 | ```
|
151 | 151 |
|
152 |
| -The execution jumps from the first `.catch` `(*)` to the next one `(**)` down the chain. |
| 152 | +Řízení skočí z prvního `.catch` `(*)` do dalšího `(**)` pod ním v řetězu. |
153 | 153 |
|
154 |
| -## Unhandled rejections |
| 154 | +## Neošetřená zamítnutí |
155 | 155 |
|
156 |
| -What happens when an error is not handled? For instance, we forgot to append `.catch` to the end of the chain, like here: |
| 156 | +Co se stane, když chyba není ošetřena? Například když zapomeneme přidat `.catch` na konec řetězu, například zde: |
157 | 157 |
|
158 | 158 | ```js untrusted run refresh
|
159 | 159 | new Promise(function() {
|
160 |
| - noSuchFunction(); // Error here (no such function) |
| 160 | + takováFunkceNení(); // zde je chyba (taková funkce není) |
161 | 161 | })
|
162 | 162 | .then(() => {
|
163 |
| - // successful promise handlers, one or more |
164 |
| - }); // without .catch at the end! |
| 163 | + // úspěšné příslibové handlery, jeden nebo více |
| 164 | + }); // bez .catch na konci! |
165 | 165 | ```
|
166 | 166 |
|
167 |
| -In case of an error, the promise becomes rejected, and the execution should jump to the closest rejection handler. But there is none. So the error gets "stuck". There's no code to handle it. |
| 167 | +V případě chyby bude příslib zamítnut a řízení by mělo skočit do nejbližšího zamítacího handleru. Tady však žádný není. Chyba tedy zůstane „viset“. Není zde žádný kód, který by ji ošetřil. |
168 | 168 |
|
169 |
| -In practice, just like with regular unhandled errors in code, it means that something has gone terribly wrong. |
| 169 | +V praxi, stejně jako u běžných neošetřených chyb v kódu, to znamená, že se něco ošklivě pokazilo. |
170 | 170 |
|
171 |
| -What happens when a regular error occurs and is not caught by `try..catch`? The script dies with a message in the console. A similar thing happens with unhandled promise rejections. |
| 171 | +Co se stane, když nastane běžná chyba a není ošetřena pomocí `try..catch`? Skript spadne se zprávou na konzoli. Něco podobného se stane u neošetřených zamítnutí příslibů. |
172 | 172 |
|
173 |
| -The JavaScript engine tracks such rejections and generates a global error in that case. You can see it in the console if you run the example above. |
| 173 | +Motor JavaScriptu tato zamítnutí sleduje a v takovém případě vygeneruje globální chybu. Můžete ji vidět na konzoli, pokud si spustíte uvedený příklad. |
174 | 174 |
|
175 |
| -In the browser we can catch such errors using the event `unhandledrejection`: |
| 175 | +V prohlížeči můžeme takové chyby zachytávat pomocí události `unhandledrejection`: |
176 | 176 |
|
177 | 177 | ```js run
|
178 | 178 | *!*
|
179 |
| -window.addEventListener('unhandledrejection', function(event) { |
180 |
| - // the event object has two special properties: |
181 |
| - alert(event.promise); // [object Promise] - the promise that generated the error |
182 |
| - alert(event.reason); // Error: Whoops! - the unhandled error object |
| 179 | +window.addEventListener('unhandledrejection', function(událost) { |
| 180 | + // objekt událost má dvě speciální vlastnosti: |
| 181 | + alert(událost.promise); // [object Promise] - příslib, který vygeneroval tuto chybu |
| 182 | + alert(událost.reason); // Error: Ouha! - neošetřený chybový objekt |
183 | 183 | });
|
184 | 184 | */!*
|
185 | 185 |
|
186 | 186 | new Promise(function() {
|
187 |
| - throw new Error("Whoops!"); |
188 |
| -}); // no catch to handle the error |
| 187 | + throw new Error("Ouha!"); |
| 188 | +}); // není zde žádné catch, které by tuto chybu ošetřilo |
189 | 189 | ```
|
190 | 190 |
|
191 |
| -The event is the part of the [HTML standard](https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections). |
| 191 | +Tato událost je součástí [standardu HTML](https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections). |
192 | 192 |
|
193 |
| -If an error occurs, and there's no `.catch`, the `unhandledrejection` handler triggers, and gets the `event` object with the information about the error, so we can do something. |
| 193 | +Jestliže dojde k chybě a není zde žádné `.catch`, spustí se handler `unhandledrejection` a obdrží objekt `událost` s informacemi o chybě, takže můžeme něco udělat. |
194 | 194 |
|
195 |
| -Usually such errors are unrecoverable, so our best way out is to inform the user about the problem and probably report the incident to the server. |
| 195 | +Z takových chyb se obvykle nelze zotavit, takže naše nejlepší cesta ven je informovat uživatele o problému a pravděpodobně hlásit tento incident serveru. |
196 | 196 |
|
197 |
| -In non-browser environments like Node.js there are other ways to track unhandled errors. |
| 197 | +V neprohlížečových prostředích, např. Node.js, existují jiné způsoby, jak vystopovat neošetřené chyby. |
198 | 198 |
|
199 |
| -## Summary |
| 199 | +## Shrnutí |
200 | 200 |
|
201 |
| -- `.catch` handles errors in promises of all kinds: be it a `reject()` call, or an error thrown in a handler. |
202 |
| -- `.then` also catches errors in the same manner, if given the second argument (which is the error handler). |
203 |
| -- We should place `.catch` exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones (maybe they are programming mistakes). |
204 |
| -- It's ok not to use `.catch` at all, if there's no way to recover from an error. |
205 |
| -- In any case we should have the `unhandledrejection` event handler (for browsers, and analogs for other environments) to track unhandled errors and inform the user (and probably our server) about them, so that our app never "just dies". |
| 201 | +- `.catch` ošetřuje chyby všech druhů v příslibech: ať je to volání `zamítni()` nebo chyba vyvolaná v handleru. |
| 202 | +- Stejným způsobem zachytává chyby také `.then`, je-li zadán druhý argument (kterým je chybový handler). |
| 203 | +- Měli bychom `.catch` umisťovat přesně na místa, kde chceme ošetřovat chyby a víme, jak je ošetřit. Handler by měl analyzovat chyby (v tom nám pomáhají vlastní chybové třídy) a opětovně vyvolat ty, které nezná (možná jde o programátorské chyby). |
| 204 | +- Vůbec nepoužít `.catch` je v pořádku, jestliže neexistuje způsob, jak se z chyby zotavit. |
| 205 | +- V každém případě bychom měli mít handler události `unhandledrejection` (pro prohlížeče, analogický handler v jiných prostředích), abychom vystopovali neošetřené chyby a informovali o nich uživatele (a pravděpodobně náš server), aby naše aplikace nikdy „jen tak nespadla“. |
0 commit comments