You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Listing 1. Asynchronous `XMLHttpRequest` (and `fetch` alternative) using a promise
33
+
Listing 1. Asynchronous `XMLHttpRequest` (and `fetch` alternative) using a promise.
28
34
29
35
The `getJSON()` function in Listing 1 returns a `promise` that resolves to some value converted from JSON data received from some remote API end point. The `fetchJSON()` function does the same, using a more modern browser Web API.
30
36
@@ -36,7 +42,7 @@ Why is a JavaScript ES6 `promise` called a 'promise'? Here is a snippet from the
36
42
noun<br>
37
43
1 a declaration or assurance that one will do something or that a particular thing will happen
38
44
39
-
This pretty well sums up what a promise means in JavaScript: something that will be delivered in the future (if and when the promise is *fulfilled*).
45
+
This pretty well sums up what a promise means in JavaScript: something that will be delivered in the future (if and when the promise is *fulfilled*).
40
46
41
47
Traditionally, *callbacks* are used as a way to receive the data that is delivered asynchronously (meaning that the data is not likely to be available at the time it is requested but can be expected 'to happen' some time later). Using callbacks can quickly become unwieldy when dealing with many asynchronous events (e.g., ajax calls), especially when they depend on each other (google for *callback hell*).
42
48
@@ -53,7 +59,7 @@ We can state a number of simple facts about ES6 promises:
53
59
-**fulfilled**: the asynchronous result has been delivered and ready (`resolve` was called)
54
60
-**rejected**: an error was encountered: the promise could not be fulfilled (`reject` was called)
55
61
- A promise that is no longer pending because it was either fulfilled to rejected is said to be _settled_.
56
-
- A promise that is _settled_ has reached its final state. Its state and value can no longer be changed.
62
+
- A promise that is _settled_ has reached its final state. Its state and value can no longer be changed. It has become _immutable_.
57
63
58
64
## The .then() method
59
65
@@ -63,7 +69,7 @@ A promise exposes a `.then()` method through which you can obtain its fulfilled
63
69
somePromise.then(onFulfilled, onRejected)
64
70
```
65
71
66
-
The `.then()` method takes two **optional**callbacks, the first one dealing with the 'happy' scenario (the promise is fulfilled) and the second one dealing with the error case (the promise is rejected). If you are only interested in the success case you can leave out the second callback:
72
+
The `.then()` method takes as its parameters two **optional**functions, the first one dealing with the 'happy' scenario (the promise is fulfilled) and the second one dealing with the error case (the promise is rejected). If you are only interested in the success case you can leave out the second parameter:
67
73
68
74
```js
69
75
somePromise.then(onFulfilled)
@@ -81,25 +87,54 @@ or you can use a second method exposed by a promise, which is just a short-hand
81
87
somePromise.catch(onRejected)
82
88
```
83
89
84
-
> Note: the callback functions passed as arguments to the `.then()` method are always called asynchronously, even if the promise was already settled.
90
+
> Note that `onFulfilled` and `onRejected` execute asynchronously, after the [event loop](./event_loop.md) turn in which then is called, and with a fresh stack.
85
91
86
-
It is also important to understand that the `.then()` method returns a new promise that resolves to the return value of the `onFulfilled`callback (if specified) in case of the 'happy' scenario or the return value of the `onRejected`callback (if specified) in case of an error. If the return value of these functions is a plain JavaScript value, the new promise is immediately fulfilled with that value. If the return value is yet another promise then that promise itself is the fulfillment value. If the function does not return a value, the new promise is immediately fulfilled with the value `undefined`.
92
+
It is also important to understand that the `.then()` method returns a new promise that resolves to the return value of `onFulfilled` (if specified) in case of the 'happy' scenario or the return value of `onRejected` (if specified) in case of an error. If the return value of these functions is a plain JavaScript value, the new promise is immediately fulfilled with that value. If the return value is yet another promise then the settlement value is of that inner promise, when settled. If the function does not return a value, the new promise is immediately fulfilled with the value `undefined`.
87
93
88
94
Because `.then()` (and `.catch`) return new promises, you can chain them together such that your code can be read as: do *this*, then do *that* and then *that*, etc.:
89
95
90
96
```js
91
-
fetchJSON(apiUrl)
97
+
getJSON(url)
92
98
.then(data=> {
93
-
renderData(data);
94
-
returnfetchJSON(otherUrl);
99
+
constinnerPromise=getJSON(otherUrl)
100
+
.then(otherData=> {
101
+
renderData(data);
102
+
renderOtherData(otherData);
103
+
});
104
+
return innerPromise;
95
105
})
96
-
.then(otherData=>renderOther(otherData))
97
-
.catch(error=>handleError(error));
106
+
.catch(err=> {
107
+
renderError(error)
108
+
});
98
109
```
99
110
100
111
Listing 2. Chaining of `then` and `catch`
101
112
102
-
More information:
113
+
Let's examine Listing 2 in a bit more detail. There two calls to `getJSON()`. Errors are to be handled in one place, by means of the `.catch()` method that terminates the promise "chain".
114
+
115
+
If you embed another promise inside the function that you pass to the `.then()` method you should return that promise as the function's return value. If you don't return the promise, you will break the promise chain and the single `.catch()` at the end of the chain will not catch all errors.
116
+
117
+
Note the expression assigned to the `innerPromise` variable. The `getJSON()` function returns a promise, but the `.then()` method chained to `getJSON()` also returns a promise (resolved to the value `undefined` because no value is returned). Therefore `innerPromise` is indeed a promise. In this case we are not interested in the value it resolves to (which is `undefined` as we saw), only in the fact that the promise is resolved (i.e. the async operation we were waiting for has been completed).
118
+
119
+
In case a promise in the chain is rejected due to some error, the promise chain will be traversed until an `onRejected` handler (e.g., in a terminating `.catch()` method) is found. All intermediate `onFulfilled` handlers (e.g. `.then()`) will be skipped*.
120
+
121
+
Handling errors at the end of a promise chain is a major advantage over the repetition of error handling code in the case of callbacks.
122
+
123
+
\* Note: `.catch(onRejected)` is a shorthand for `.then(null, onRejected)`.
124
+
125
+
## Further readings
126
+
127
+
Our previous students also enjoyed learning about promises at:
0 commit comments