You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
**Throwing an exception is also considered an error.**
210
209
211
-
For instance:
210
+
### Implicit try..catch
211
+
212
+
Throwing an exception is considered a rejection.
213
+
214
+
For instance, this code:
212
215
213
216
```js run
214
217
newPromise(function(resolve, reject) {
218
+
*!*
215
219
thrownewError("Whoops!");
220
+
*/!*
216
221
}).catch(function(error) {
217
222
alert(error.message); // Whoops!
218
223
});
224
+
```
219
225
220
-
## Inheriting from promise, thenables, error handling?
226
+
...Works the same way as:
221
227
222
-
An object that has a method called `.then` is called a "thenable".
228
+
```js run
229
+
newPromise(function(resolve, reject) {
230
+
*!*
231
+
reject(newError("Whoops!"));
232
+
*/!*
233
+
}).catch(function(error) {
234
+
alert(error.message); // Whoops!
235
+
});
236
+
```
223
237
224
-
Instead of checking if something is `instanceof Promise`, we should usually check it for being thenable, and if it is, then treat it as a promise ("duck typing").
238
+
Like there's an invisible `try..catch` around the whole code of the function, that catches errors.
225
239
226
-
JavaScript specification also checks the value returned by a handler for being a thenable, not exactly a promise, when it decides whether to pass it along the chain or wait for the result. Sointhe examples above we could use custom thenables instead of`Promise` instances.
240
+
That works not only in the executor, but in handlers as well, for instance:
227
241
228
-
For instance, native promises give no way to "abort" the execution. The`loadScript` above cannot "cancel" script loading, just because there's no `.abort` method on promises, we can only listen for the state change using `.then/catch`.
242
+
```js run
243
+
newPromise(function(resolve, reject) {
244
+
resolve("ok")
245
+
}).then(function(result) {
246
+
*!*
247
+
thrownewError("Whoops!");
248
+
*/!*
249
+
})
250
+
.catch(function(error) {
251
+
alert(error.message); // Whoops!
252
+
});
253
+
```
229
254
230
-
Let's
231
255
256
+
### Rethrowing
232
257
258
+
As we already noticed, `.catch` is like `try..catch`. We may have as many `.then` as we want, and then use a single `.catch` at the end to handle errors in all of them.
233
259
260
+
In a regular `try..catch` we can analyze the error and maybe rethrow it can't handle. The same thing is possible for promises.
234
261
262
+
A handler in `.catch` can finish in two ways:
235
263
264
+
1. It can return a value or don't return anything. Then the execution continues "normally", the next `.then(onResolved)` handler is called.
265
+
2. It can throw an error. Then the execution goes the "error" path, and the closest rejection handler is called.
236
266
267
+
Here is an example of the first behavior (the error is handled):
237
268
269
+
```js run
270
+
// the execution: catch -> then
271
+
newPromise(function(resolve, reject) {
238
272
239
-
## Error handling
273
+
thrownewError("Whoops!");
240
274
275
+
}).catch(function(error) {
241
276
277
+
alert("Handled it!");
278
+
*!*
279
+
return"result"; // return, the execution goes the "normal way"
280
+
*/!*
242
281
282
+
*!*
283
+
}).then(alert); // result shown
284
+
*/!*
285
+
```
243
286
287
+
...And here's an example of "rethrowing":
244
288
245
289
246
290
```js run
291
+
// the execution: catch -> catch -> then
247
292
newPromise(function(resolve, reject) {
248
-
setTimeout(() => resolve(1), 1000);
249
-
}).then(function(result) {
250
293
251
294
thrownewError("Whoops!");
252
295
253
296
}).catch(function(error) {
254
297
255
-
alert(error.message); // Whoops!
298
+
alert("Can't handle!");
299
+
*!*
300
+
throw error; // throwing this or another error jumps to the next catch
301
+
*/!*
302
+
303
+
}).catch(error=> {
256
304
305
+
alert("Trying to handle again...");
306
+
// don't return anything => execution goes the normal way
307
+
308
+
}).then(alert); // undefined
309
+
```
310
+
311
+
### Unhandled rejections
312
+
313
+
What if we forget to handle an error?
314
+
315
+
Like here:
316
+
317
+
```js untrusted run refresh
318
+
newPromise(function() {
319
+
errorHappened(); // Error here (no such function)
257
320
});
258
321
```
259
322
323
+
Or here:
260
324
325
+
```js untrusted run refresh
326
+
newPromise(function() {
327
+
thrownewError("Whoops!");
328
+
}).then(function() {
329
+
// ...something...
330
+
}).then(function() {
331
+
// ...something else...
332
+
}).then(function() {
333
+
// ...but no catch after it!
334
+
});
335
+
```
261
336
337
+
Technically, when an error happens, the promise state becomes "rejected", and the execution should jump to the closest rejection handler. But there is none.
262
338
263
-
The idea is :
339
+
Usually that means that the code is bad. Most JavaScript engines track such situations and generate a global error. In the browser we can catch it using `window.addEventListener('unhandledrejection')` (as specified in the [HTML standard](https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections)):
alert(event.promise); // the promise that generated the error
347
+
alert(event.reason); // the error itself (Whoops!)
348
+
});
349
+
350
+
newPromise(function() {
351
+
thrownewError("Whoops!");
352
+
}).then(function() {
353
+
// ...something...
354
+
}).then(function() {
355
+
// ...something else...
356
+
}).then(function() {
357
+
// ...but no catch after it!
358
+
});
359
+
```
360
+
361
+
In non-browser environments there's also a similar event, so we can always track unhandled errors in promises.
362
+
363
+
364
+
An object that has a method called `.then` is called a "thenable".
365
+
366
+
Instead of checking if something is `instanceof Promise`, we should usually check it for being thenable, and if it is, then treat it as a promise ("duck typing").
367
+
368
+
JavaScript specification also checks the value returned by a handler for being a thenable, not exactly a promise, when it decides whether to pass it along the chain or wait for the result. So in the examples above we could use custom thenables instead of `Promise` instances.
369
+
370
+
For instance, native promises give no way to "abort" the execution. The `loadScript` above cannot "cancel" script loading, just because there's no `.abort` method on promises, we can only listen for the state change using `.then/catch`.
371
+
372
+
## Extending promises, thenables
373
+
374
+
Promises are very simple by design. One of the thing they miss is the ability to cancel the process.
375
+
376
+
For instance, `loadScript(src)` in previous examples returns a promise that allows to track success/failure of the loading. But can we abort it? No.
377
+
378
+
We can inherit from `Promise` to introduce such functionality, like this:
379
+
380
+
381
+
// TODO: NOT WORKING AS INTENDED?
382
+
383
+
```js run
384
+
functionloadScript(src) {
385
+
let script =document.createElement('script');
386
+
script.src= src;
387
+
388
+
let promise =newPromise(function(resolve, reject) {
0 commit comments