From a4a16fccd690498e990c70372b3be3001f26bebe Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Mon, 17 Apr 2017 21:42:33 +0200 Subject: [PATCH] minor --- .../04-object-methods/article.md | 2 +- .../07-map-set-weakmap-weakset/article.md | 2 +- 1-js/05-data-types/11-json/article.md | 2 +- .../10-class-inheritance/article.md | 2 +- 1-js/08-error-handling/1-try-catch/article.md | 2 +- .../2-custom-errors/article.md | 4 +- 8-async/03-promise-chaining/article.md | 102 +++++++++++++++--- 8-async/03-promise-chaining/head.html | 15 +-- 8 files changed, 105 insertions(+), 26 deletions(-) diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md index 0e593237..81296278 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -161,7 +161,7 @@ let user = { let admin = user; 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. diff --git a/1-js/05-data-types/07-map-set-weakmap-weakset/article.md b/1-js/05-data-types/07-map-set-weakmap-weakset/article.md index fa5c9af5..a09edda5 100644 --- a/1-js/05-data-types/07-map-set-weakmap-weakset/article.md +++ b/1-js/05-data-types/07-map-set-weakmap-weakset/article.md @@ -287,7 +287,7 @@ let obj = {}; 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 */!* ``` diff --git a/1-js/05-data-types/11-json/article.md b/1-js/05-data-types/11-json/article.md index a498848e..488c88b5 100644 --- a/1-js/05-data-types/11-json/article.md +++ b/1-js/05-data-types/11-json/article.md @@ -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`? diff --git a/1-js/07-object-oriented-programming/10-class-inheritance/article.md b/1-js/07-object-oriented-programming/10-class-inheritance/article.md index 4fb012e2..57fef34a 100644 --- a/1-js/07-object-oriented-programming/10-class-inheritance/article.md +++ b/1-js/07-object-oriented-programming/10-class-inheritance/article.md @@ -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`. diff --git a/1-js/08-error-handling/1-try-catch/article.md b/1-js/08-error-handling/1-try-catch/article.md index 19ca9b79..25b70d10 100644 --- a/1-js/08-error-handling/1-try-catch/article.md +++ b/1-js/08-error-handling/1-try-catch/article.md @@ -612,7 +612,7 @@ For instance: */!* function readData() { - badFunc(); // Woops, something went wrong! + badFunc(); // Whoops, something went wrong! } readData(); diff --git a/1-js/08-error-handling/2-custom-errors/article.md b/1-js/08-error-handling/2-custom-errors/article.md index b2e48858..709cd359 100644 --- a/1-js/08-error-handling/2-custom-errors/article.md +++ b/1-js/08-error-handling/2-custom-errors/article.md @@ -47,13 +47,13 @@ class ValidationError extends Error { } function test() { - throw new ValidationError("Woops!"); + throw new ValidationError("Whoops!"); } try { test(); } catch(err) { - alert(err.message); // Woops! + alert(err.message); // Whoops! alert(err.name); // ValidationError alert(err.stack); // a list of nested calls with line numbers for each } diff --git a/8-async/03-promise-chaining/article.md b/8-async/03-promise-chaining/article.md index 04af44cc..c518a872 100644 --- a/8-async/03-promise-chaining/article.md +++ b/8-async/03-promise-chaining/article.md @@ -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. -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 -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") .then(function(script) { 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". +## 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? An object that has a method called `.then` is called a "thenable". diff --git a/8-async/03-promise-chaining/head.html b/8-async/03-promise-chaining/head.html index e93cd69e..8dd44050 100644 --- a/8-async/03-promise-chaining/head.html +++ b/8-async/03-promise-chaining/head.html @@ -1,10 +1,13 @@