diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/03-symbol/article.md index 90e2dfb9..dd31b138 100644 --- a/1-js/04-object-basics/03-symbol/article.md +++ b/1-js/04-object-basics/03-symbol/article.md @@ -113,8 +113,8 @@ let user = { for(let key in user) alert(key); // name, age (no symbols) */!* -// the direct access by the global symbol works -alert( "Direct: " + user[Symbol.for("id")] ); +// the direct access by the symbol works +alert( "Direct: " + user[id] ); ``` That's a part of the general "hiding" concept. If another script or a library loops over our object, it won't unexpectedly access a symbolic property. diff --git a/8-async/02-promise-basics/01-re-resolve/solution.md b/8-async/02-promise-basics/01-re-resolve/solution.md new file mode 100644 index 00000000..57046a25 --- /dev/null +++ b/8-async/02-promise-basics/01-re-resolve/solution.md @@ -0,0 +1,3 @@ +The output is: `1`. + +The second call to `resolve` is ignored, because only the first call of `reject/resolve` is taken into account. Further calls are ignored. diff --git a/8-async/02-promise-basics/01-re-resolve/task.md b/8-async/02-promise-basics/01-re-resolve/task.md new file mode 100644 index 00000000..185806ed --- /dev/null +++ b/8-async/02-promise-basics/01-re-resolve/task.md @@ -0,0 +1,15 @@ + +# Re-resolve a promise? + + +What's the output of the code below? + +```js +let promise = new Promise(function(resolve, reject) { + resolve(1); + + setTimeout(() => resolve(2), 1000); +}); + +promise.then(alert); +``` diff --git a/8-async/02-promise-basics/article.md b/8-async/02-promise-basics/article.md index bf96df84..9310e5bc 100644 --- a/8-async/02-promise-basics/article.md +++ b/8-async/02-promise-basics/article.md @@ -1,11 +1,5 @@ # Promise - -```compare plus="Plus" minus="Minus" -+ One -- two -``` - A promise is an object of the built-in `Promise` class. The promise object has two main internal properties: `state` and the `result`. @@ -224,98 +218,59 @@ promise.then( promise.then(script => alert('One more handler to do something else!')); ``` -We can immediately see few benefits over the callback-based syntax in the example above. +We can immediately see few benefits over the callback-based syntax: -| Callbacks | Promises | -|-----------|----------| -| We must have `callback` function when calling `loadScript`. So we must know what to do with the result *before* we make a call for it. | Promises allow us to code more naturally. First we run `loadScript`, then code what we do with the result. | -|There can be only one callback. | We can call `.then` as many times as we want. | - - -We can call `promise.then` at any time. Maybe much later, when we really need that script. - -1. We can call `promise.then` as many times as want, so we can add any number of handlers. -3. The `promise` object can be passed around, new handlers can be added where needed in other parts of the code. - -So promises give us flexibility. But there's more. We can chain promises and use `async` functions and so on. We'll see that in the next chapters. - -Read the notes below for better understanding of promise objects. - -````warn header="Once a promise settles, it can't be changed" -When either `resolve` or `reject` is called -- the state change is final. The argument of `resolve/reject` is saved in the promise object. - -Future calls of `resolve/reject` are ignored, so there's no way to "re-resolve" or "re-reject" a promise. - -For instance, here only the first `resolve` works: - -```js run -let promise = new Promise(function(resolve, reject) { - resolve("done!"); // immediately fulfill with the result: "done" - - // a subsequent resolve is ignored - setTimeout(() => resolve("..."), 1000); - // a subsequent reject is ignored - setTimeout(() => reject(new Error("..."), 2000)); -}); - -promise.then(result => alert(result), () => alert("Never runs")); -``` -```` - - -````smart header="A promise may resolve immediately, doesn't have to be asynchronous" -As we've seen from the example above, a promise may call resolve/reject without delay: - -```js run -new Promise(function(resolve, reject) { - resolve("done!"); // immediately fulfill with the result: "done" -}).then(alert); +```compare minus="Callbacks" plus="Promises" +- We must have `callback` function available when calling `loadScript`. So we must know what to do with the result *before* we make a call for it. +- There can be only one callback. ++ Promises allow us to code more naturally. First we run `loadScript`, and `.then` code what we do with the result. ++ We can call `.then` as many times as we want. ``` -That's normal, sometimes it turns out that there's no asynchronous job to be done. For instance, if we have a cached result. -```` + +So promises give us better code flow and flexibility. But there's more. We'll see that in the next chapters. ````smart header="On settled promises `then` runs immediately" We can add `.then/catch` at any time. -If the promise has not settled yet, then it will wait for the result. - -Otherwise, if the promise has already resolved/rejected, then subsequent `promise.then/catch` handlers are executed immediately. - -To be precise -- they are still asynchronous, but run as soon as possible, similar to `setTimeout(...,0)`. - -For instance, here we'll first see "code end", and then "done!": +If the promise has not settled yet, then it will wait for the result. Otherwise, if the promise has already settled, then `promise.then/catch` handlers run immediately: ```js run -// the promise is in the "resolved" state immediately -let promise = new Promise(function(resolve, reject) { - resolve("done!"); -}); +let promise = new Promise(resolve => resolve("done!")); // immediately resolve -// the handler runs as soon as possible, but asynchronously, like setTimeout(...,0) -promise.then(alert); +promise.then(alert); // done! (without delay) +``` -alert('code end'); + +To be precise -- handlers are always asynchronous, but if the promise is settled they run as soon as possible, similar to `setTimeout(...,0)`. + +For instance, here we'll first see "code end" `(1)`, and then "done!" `(2)`: + +```js run +let promise = new Promise(resolve => resolve("done!")); + +// alert runs as soon as possible, but asynchronously, +// like if it were wrapped in setTimeout(..., 0); +promise.then(alert); // (2) + +alert('code end'); // (1) ``` ```` -````smart header="Functions resolve/reject have only one argument" +````smart header="Functions resolve/reject accept at most one argument" Functions `resolve/reject` accept only one argument. -We can call them without any arguments too. The call `resolve()` makes the result `undefined`: +We can call them without any arguments too, that's the same as passing `undefined`: ```js run -let promise = new Promise(function(resolve, reject) { - resolve(); -}); +let promise = new Promise(resolve => resolve()); -promise.then(result => alert(result)); // undefined +promise.then(alert); // undefined ``` -...But if we pass many arguments: `resolve(1, 2, 3)`, then all arguments after the first one are ignored. A promise may have only one value as a result/error. - -Use objects and destructuring if you need to pass many values, like this: +...But if we pass many arguments: `resolve(1, 2, 3)`, then all arguments after the first one are ignored. +The idea is that a promise may have only one result (or an error). Use objects and destructuring if you need to pass many values, like this: ```js run let promise = new Promise(function(resolve, reject) { diff --git a/8-async/03-promise-chaining/article.md b/8-async/03-promise-chaining/article.md index dd29a919..7c8fcdd0 100644 --- a/8-async/03-promise-chaining/article.md +++ b/8-async/03-promise-chaining/article.md @@ -3,17 +3,14 @@ Let's formulate the problem mentioned in the chapter : -- We have a sequence of tasks to be done one after another. For instance, loading scripts. The next task may need the result of the previous one. +- We have a sequence of asynchronous tasks to be done one after another. For instance, loading scripts. - How to code it well? -Promises can cover that need in two ways: +Promises allow a couple of recipes to do that. -1. Promises chaining. -2. Async functions. +[cut] -Let's see the first way in this chapter and the second one in the next. - -Promises chaining looks like this: +In this chapter we cover promise chaining. It looks like this: ```js run new Promise(function(resolve, reject) { @@ -36,12 +33,17 @@ new Promise(function(resolve, reject) { return result * 2; }); -// ... ``` -As we can see, a call to `promise.then` returns a promise, that we can use again for `.then`. A value returned by `.then` becomes a result in the next `.then`. So in the example above we have a sequence of results: `1` -> `2` -> `4`. +As we can see: +- A call to `promise.then` returns a promise, that we can use for the next `.then` (chaining). +- A value returned by `.then` handler becomes a result in the next `.then`. -Please note that chaining `.then` is not the same as many `.then` on a single promise, like below: +![](promise-then-chain.png) + +So in the example above we have a sequence of results: `1` -> `2` -> `4`. + +Please note the difference between chained `.then` and many `.then` on a single promise, like below: ```js run let promise = new Promise(function(resolve, reject) { @@ -66,6 +68,8 @@ promise.then(function(result) { In the code above, all `.then` are on the same promise, so all of them get the same result -- the result of that promise. And all `alert` show the same: 1. +![](promise-then-many.png) + If we want to use the value returned by a handler of `.then`, then we should add a new `.then` after it (to chain). ## Returning promises diff --git a/8-async/03-promise-chaining/promise-then-chain.png b/8-async/03-promise-chaining/promise-then-chain.png new file mode 100644 index 00000000..7d745b0c Binary files /dev/null and b/8-async/03-promise-chaining/promise-then-chain.png differ diff --git a/8-async/03-promise-chaining/promise-then-chain@2x.png b/8-async/03-promise-chaining/promise-then-chain@2x.png new file mode 100644 index 00000000..e3d7b2bd Binary files /dev/null and b/8-async/03-promise-chaining/promise-then-chain@2x.png differ diff --git a/8-async/03-promise-chaining/promise-then-many.png b/8-async/03-promise-chaining/promise-then-many.png new file mode 100644 index 00000000..83c1f1e7 Binary files /dev/null and b/8-async/03-promise-chaining/promise-then-many.png differ diff --git a/8-async/03-promise-chaining/promise-then-many@2x.png b/8-async/03-promise-chaining/promise-then-many@2x.png new file mode 100644 index 00000000..318124ef Binary files /dev/null and b/8-async/03-promise-chaining/promise-then-many@2x.png differ diff --git a/figures.sketch b/figures.sketch index 22b179f6..f2d44924 100644 Binary files a/figures.sketch and b/figures.sketch differ