minor
This commit is contained in:
parent
8fc01fa0fe
commit
a4a16fccd6
8 changed files with 105 additions and 26 deletions
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
*/!*
|
*/!*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -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`?
|
||||||
|
|
||||||
|
|
|
@ -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`.
|
||||||
|
|
||||||
|
|
|
@ -612,7 +612,7 @@ For instance:
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
function readData() {
|
function readData() {
|
||||||
badFunc(); // Woops, something went wrong!
|
badFunc(); // Whoops, something went wrong!
|
||||||
}
|
}
|
||||||
|
|
||||||
readData();
|
readData();
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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".
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue