minor
This commit is contained in:
parent
e80667391f
commit
8bd8e90488
5 changed files with 36 additions and 191 deletions
|
@ -48,24 +48,6 @@ The whole thing works, because a call to `promise.then` returns a promise, so th
|
|||
|
||||
When a handler returns a value, it becomes the result of that promise, so the next `.then` is called with it.
|
||||
|
||||
To make these words more clear, here's the start of the chain:
|
||||
|
||||
```js run
|
||||
new Promise(function(resolve, reject) {
|
||||
|
||||
setTimeout(() => resolve(1), 1000);
|
||||
|
||||
}).then(function(result) {
|
||||
|
||||
alert(result);
|
||||
return result * 2; // <-- (1)
|
||||
|
||||
}) // <-- (2)
|
||||
// .then…
|
||||
```
|
||||
|
||||
The value returned by `.then` is a promise, that's why we are able to add another `.then` at `(2)`. When the value is returned in `(1)`, that promise becomes resolved, so the next handler runs with the value.
|
||||
|
||||
**A classic newbie error: technically we can also add many `.then` to a single promise. This is not chaining.**
|
||||
|
||||
For example:
|
||||
|
@ -138,9 +120,9 @@ new Promise(function(resolve, reject) {
|
|||
});
|
||||
```
|
||||
|
||||
Here the first `.then` shows `1` and returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result*2`) is passed on to handler of the second `.then` in the line `(**)`. It shows `2` and does the same thing.
|
||||
Here the first `.then` shows `1` and returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result * 2`) is passed on to handler of the second `.then`. That handler is in the line `(**)`, it shows `2` and does the same thing.
|
||||
|
||||
So the output is again 1 -> 2 -> 4, but now with 1 second delay between `alert` calls.
|
||||
So the output is the same as in the previous example: 1 -> 2 -> 4, but now with 1 second delay between `alert` calls.
|
||||
|
||||
Returning promises allows us to build chains of asynchronous actions.
|
||||
|
||||
|
@ -184,7 +166,7 @@ Here each `loadScript` call returns a promise, and the next `.then` runs when it
|
|||
|
||||
We can add more asynchronous actions to the chain. Please note that code is still "flat", it grows down, not to the right. There are no signs of "pyramid of doom".
|
||||
|
||||
Please note that technically we can add `.then` directly to each `loadScript`, like this:
|
||||
Technically, we could add `.then` directly to each `loadScript`, like this:
|
||||
|
||||
```js run
|
||||
loadScript("/article/promise-chaining/one.js").then(script1 => {
|
||||
|
@ -207,7 +189,7 @@ Sometimes it's ok to write `.then` directly, because the nested function has acc
|
|||
|
||||
|
||||
````smart header="Thenables"
|
||||
To be precise, `.then` may return a so-called "thenable" object - an arbitrary object that has method `.then`, and it will be treated the same way as a promise.
|
||||
To be precise, a handler may return not exactly a promise, but a so-called "thenable" object - an arbitrary object that has method `.then`, and it will be treated the same way as a promise.
|
||||
|
||||
The idea is that 3rd-party libraries may implement "promise-compatible" objects of their own. They can have extended set of methods, but also be compatible with native promises, because they implement `.then`.
|
||||
|
||||
|
@ -227,7 +209,9 @@ class Thenable {
|
|||
|
||||
new Promise(resolve => resolve(1))
|
||||
.then(result => {
|
||||
*!*
|
||||
return new Thenable(result); // (*)
|
||||
*/!*
|
||||
})
|
||||
.then(alert); // shows 2 after 1000ms
|
||||
```
|
||||
|
@ -242,7 +226,7 @@ This feature allows to integrate custom objects with promise chains without havi
|
|||
|
||||
In frontend programming promises are often used for network requests. So let's see an extended example of that.
|
||||
|
||||
We'll use the [fetch](info:fetch) method to load the information about the user from the remote server. It has a lot of optional parameters covered in separate chapters, but the basic syntax is quite simple:
|
||||
We'll use the [fetch](info:fetch) method to load the information about the user from the remote server. It has a lot of optional parameters covered in [separate chapters](info:fetch), but the basic syntax is quite simple:
|
||||
|
||||
```js
|
||||
let promise = fetch(url);
|
||||
|
@ -259,7 +243,7 @@ fetch('/article/promise-chaining/user.json')
|
|||
// .then below runs when the remote server responds
|
||||
.then(function(response) {
|
||||
// response.text() returns a new promise that resolves with the full response text
|
||||
// when we finish downloading it
|
||||
// when it loads
|
||||
return response.text();
|
||||
})
|
||||
.then(function(text) {
|
||||
|
@ -276,7 +260,7 @@ We'll also use arrow functions for brevity:
|
|||
// same as above, but response.json() parses the remote content as JSON
|
||||
fetch('/article/promise-chaining/user.json')
|
||||
.then(response => response.json())
|
||||
.then(user => alert(user.name)); // iliakan
|
||||
.then(user => alert(user.name)); // iliakan, got user name
|
||||
```
|
||||
|
||||
Now let's do something with the loaded user.
|
||||
|
@ -317,7 +301,7 @@ fetch('/article/promise-chaining/user.json')
|
|||
.then(user => fetch(`https://api.github.com/users/${user.name}`))
|
||||
.then(response => response.json())
|
||||
*!*
|
||||
.then(githubUser => new Promise(function(resolve, reject) {
|
||||
.then(githubUser => new Promise(function(resolve, reject) { // (*)
|
||||
*/!*
|
||||
let img = document.createElement('img');
|
||||
img.src = githubUser.avatar_url;
|
||||
|
@ -327,7 +311,7 @@ fetch('/article/promise-chaining/user.json')
|
|||
setTimeout(() => {
|
||||
img.remove();
|
||||
*!*
|
||||
resolve(githubUser);
|
||||
resolve(githubUser); // (**)
|
||||
*/!*
|
||||
}, 3000);
|
||||
}))
|
||||
|
@ -335,9 +319,11 @@ fetch('/article/promise-chaining/user.json')
|
|||
.then(githubUser => alert(`Finished showing ${githubUser.name}`));
|
||||
```
|
||||
|
||||
Now right after `setTimeout` runs `img.remove()`, it calls `resolve(githubUser)`, thus passing the control to the next `.then` in the chain and passing forward the user data.
|
||||
That is, `.then` handler in the line `(*)` now returns `new Promise`, that becomes settled only after the call of `resolve(githubUser)` in `setTimeout` `(**)`.
|
||||
|
||||
As a rule, an asynchronous action should always return a promise.
|
||||
The next `.then` in chain will wait for that.
|
||||
|
||||
As a good rule, an asynchronous action should always return a promise.
|
||||
|
||||
That makes it possible to plan actions after it. Even if we don't plan to extend the chain now, we may need it later.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue