This commit is contained in:
Ilya Kantor 2017-04-17 21:42:33 +02:00
parent 8fc01fa0fe
commit a4a16fccd6
8 changed files with 105 additions and 26 deletions

View file

@ -161,7 +161,7 @@ let user = {
let admin = user; let admin = user;
user = null; // overwrite to make things obvious user = null; // overwrite to make things obvious
admin.sayHi(); // Woops! inside sayHi(), the old name is used! error! admin.sayHi(); // Whoops! inside sayHi(), the old name is used! error!
``` ```
If we used `this.name` instead of `user.name` inside the `alert`, then the code would work. If we used `this.name` instead of `user.name` inside the `alert`, then the code would work.

View file

@ -287,7 +287,7 @@ let obj = {};
weakMap.set(obj, "ok"); // works fine (object key) weakMap.set(obj, "ok"); // works fine (object key)
*!* *!*
weakMap.set("test", "Woops"); // Error, because "test" is a primitive weakMap.set("test", "Whoops"); // Error, because "test" is a primitive
*/!* */!*
``` ```

View file

@ -477,7 +477,7 @@ alert( meetup.date.getDate() ); // Error!
*/!* */!*
``` ```
Woops! An error! Whoops! An error!
The value of `meetup.date` is a string, not a `Date` object. How `JSON.parse` may know that it should transform that string into a `Date`? The value of `meetup.date` is a string, not a `Date` object. How `JSON.parse` may know that it should transform that string into a `Date`?

View file

@ -210,7 +210,7 @@ let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined.
*/!* */!*
``` ```
Woops! We've got an error. Now we can't create rabbits. What went wrong? Whoops! We've got an error. Now we can't create rabbits. What went wrong?
The short answer is: constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`. The short answer is: constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`.

View file

@ -612,7 +612,7 @@ For instance:
*/!* */!*
function readData() { function readData() {
badFunc(); // Woops, something went wrong! badFunc(); // Whoops, something went wrong!
} }
readData(); readData();

View file

@ -47,13 +47,13 @@ class ValidationError extends Error {
} }
function test() { function test() {
throw new ValidationError("Woops!"); throw new ValidationError("Whoops!");
} }
try { try {
test(); test();
} catch(err) { } catch(err) {
alert(err.message); // Woops! alert(err.message); // Whoops!
alert(err.name); // ValidationError alert(err.name); // ValidationError
alert(err.stack); // a list of nested calls with line numbers for each alert(err.stack); // a list of nested calls with line numbers for each
} }

View file

@ -110,21 +110,9 @@ Now we have the same 1 -> 2 > 4 output, but with 1 second delay between each.
When we return `new Promise(…)`, the next `.then` in the chain is executed when it settles and gets its result. When we return `new Promise(…)`, the next `.then` in the chain is executed when it settles and gets its result.
Let's use it to `loadScript` multiple scripts one by one: Let's use it with `loadScript` to load multiple scripts one by one, in sequence:
```js run ```js run
function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = () => reject(new Error("Script load error: " + src));
document.head.append(script);
});
}
loadScript("/article/promise-chaining/one.js") loadScript("/article/promise-chaining/one.js")
.then(function(script) { .then(function(script) {
return loadScript("/article/promise-chaining/two.js"); return loadScript("/article/promise-chaining/two.js");
@ -139,8 +127,96 @@ loadScript("/article/promise-chaining/one.js")
}); });
``` ```
The code totally evades the pyramid of doom. We can add more asynchronous actions to the chain, and the code is still "flat". The code totally evades the pyramid of doom. We can add more asynchronous actions to the chain, and the code is still "flat".
## Error handling
In case of an error, the closest `onRejected` handler down the chain is called.
Let's recall that a rejection (error) handler may be assigned with two syntaxes:
- `.then(...,onRejected)`, as a second argument of `.then`.
- `.catch(onRejected)`, a shorthand for `.then(null, onRejected)`.
In the example below we use the second syntax to catch all errors in the script load chain:
```js run
function loadScript(src) {
return new Promise(function(resolve, reject) {
let script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
*!*
script.onerror = () => reject(new Error("Script load error: " + src)); // (*)
*/!*
document.head.append(script);
});
}
*!*
loadScript("/article/promise-chaining/ERROR.js")
*/!*
.then(function(script) {
return loadScript("/article/promise-chaining/two.js");
})
.then(function(script) {
return loadScript("/article/promise-chaining/three.js");
})
.then(function(script) {
// use variables declared in scripts
// to show that they indeed loaded
alert("Done: " + (one + two + three));
})
*!*
.catch(function(error) { // (**)
alert(error.message);
});
*/!*
```
In the code above the first `loadScript` call fails, because `ERROR.js` doesn't exist. The initial error is generated in the line `(*)`, then the first error handler in the chain is called, that is `(**)`.
Now the same thing, but the error occurs in the second script:
```js run
loadScript("/article/promise-chaining/one.js")
.then(function(script) {
*!*
return loadScript("/article/promise-chaining/ERROR.js");
*/!*
})
.then(function(script) {
return loadScript("/article/promise-chaining/three.js");
})
.then(function(script) {
// use variables declared in scripts
// to show that they indeed loaded
alert("Done: " + (one + two + three));
})
*!*
.catch(function(error) {
alert(error.message);
});
*/!*
```
Once again, the `.catch` handles it.
**Throwing an exception is also considered an error.**
For instance:
```js run
new Promise(function(resolve, reject) {
throw new Error("Woops!");
}).catch(function(error) {
alert(error.message); // Whoops
});
## Inheriting from promise, thenables, error handling? ## Inheriting from promise, thenables, error handling?
An object that has a method called `.then` is called a "thenable". An object that has a method called `.then` is called a "thenable".

View file

@ -1,10 +1,13 @@
<script> <script>
function loadImage(src) { function loadScript(src) {
return new Promise((resolve, reject) => { return new Promise(function(resolve, reject) {
let img = document.createElement('img'); let script = document.createElement('script');
img.src = src; script.src = src;
img.onload = () => resolve(img);
img.onerror = () => reject(new Error("Image load failed: " + src)); script.onload = () => resolve(script);
script.onerror = () => reject(new Error("Script load error: " + src));
document.head.append(script);
}); });
} }
</script> </script>