up
This commit is contained in:
parent
543680aeeb
commit
75895f44b8
10 changed files with 65 additions and 88 deletions
|
@ -113,8 +113,8 @@ let user = {
|
||||||
for(let key in user) alert(key); // name, age (no symbols)
|
for(let key in user) alert(key); // name, age (no symbols)
|
||||||
*/!*
|
*/!*
|
||||||
|
|
||||||
// the direct access by the global symbol works
|
// the direct access by the symbol works
|
||||||
alert( "Direct: " + user[Symbol.for("id")] );
|
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.
|
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.
|
||||||
|
|
3
8-async/02-promise-basics/01-re-resolve/solution.md
Normal file
3
8-async/02-promise-basics/01-re-resolve/solution.md
Normal file
|
@ -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.
|
15
8-async/02-promise-basics/01-re-resolve/task.md
Normal file
15
8-async/02-promise-basics/01-re-resolve/task.md
Normal file
|
@ -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);
|
||||||
|
```
|
|
@ -1,11 +1,5 @@
|
||||||
# Promise
|
# Promise
|
||||||
|
|
||||||
|
|
||||||
```compare plus="Plus" minus="Minus"
|
|
||||||
+ One
|
|
||||||
- two
|
|
||||||
```
|
|
||||||
|
|
||||||
A promise is an object of the built-in `Promise` class.
|
A promise is an object of the built-in `Promise` class.
|
||||||
|
|
||||||
The promise object has two main internal properties: `state` and the `result`.
|
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!'));
|
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 |
|
```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.
|
||||||
| 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.
|
||||||
|There can be only one callback. | We can call `.then` as many times as we want. |
|
+ 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.
|
||||||
|
|
||||||
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);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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"
|
````smart header="On settled promises `then` runs immediately"
|
||||||
We can add `.then/catch` at any time.
|
We can add `.then/catch` at any time.
|
||||||
|
|
||||||
If the promise has not settled yet, then it will wait for the result.
|
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:
|
||||||
|
|
||||||
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!":
|
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
// the promise is in the "resolved" state immediately
|
let promise = new Promise(resolve => resolve("done!")); // immediately resolve
|
||||||
let promise = new Promise(function(resolve, reject) {
|
|
||||||
resolve("done!");
|
|
||||||
});
|
|
||||||
|
|
||||||
// the handler runs as soon as possible, but asynchronously, like setTimeout(...,0)
|
promise.then(alert); // done! (without delay)
|
||||||
promise.then(alert);
|
```
|
||||||
|
|
||||||
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.
|
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
|
```js run
|
||||||
let promise = new Promise(function(resolve, reject) {
|
let promise = new Promise(resolve => 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.
|
...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:
|
||||||
Use objects and destructuring if you need to pass many values, like this:
|
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
let promise = new Promise(function(resolve, reject) {
|
let promise = new Promise(function(resolve, reject) {
|
||||||
|
|
|
@ -3,17 +3,14 @@
|
||||||
|
|
||||||
Let's formulate the problem mentioned in the chapter <info:callback-hell>:
|
Let's formulate the problem mentioned in the chapter <info:callback-hell>:
|
||||||
|
|
||||||
- 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?
|
- 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.
|
[cut]
|
||||||
2. Async functions.
|
|
||||||
|
|
||||||
Let's see the first way in this chapter and the second one in the next.
|
In this chapter we cover promise chaining. It looks like this:
|
||||||
|
|
||||||
Promises chaining looks like this:
|
|
||||||
|
|
||||||
```js run
|
```js run
|
||||||
new Promise(function(resolve, reject) {
|
new Promise(function(resolve, reject) {
|
||||||
|
@ -36,12 +33,17 @@ new Promise(function(resolve, reject) {
|
||||||
return result * 2;
|
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:
|

|
||||||
|
|
||||||
|
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
|
```js run
|
||||||
let promise = new Promise(function(resolve, reject) {
|
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.
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
If we want to use the value returned by a handler of `.then`, then we should add a new `.then` after it (to chain).
|
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
|
## Returning promises
|
||||||
|
|
BIN
8-async/03-promise-chaining/promise-then-chain.png
Normal file
BIN
8-async/03-promise-chaining/promise-then-chain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
BIN
8-async/03-promise-chaining/promise-then-chain@2x.png
Normal file
BIN
8-async/03-promise-chaining/promise-then-chain@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
8-async/03-promise-chaining/promise-then-many.png
Normal file
BIN
8-async/03-promise-chaining/promise-then-many.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
BIN
8-async/03-promise-chaining/promise-then-many@2x.png
Normal file
BIN
8-async/03-promise-chaining/promise-then-many@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
figures.sketch
BIN
figures.sketch
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue