Skip to content

Commit bb6667a

Browse files
committed
closes #3061
1 parent 965bd68 commit bb6667a

File tree

1 file changed

+44
-21
lines changed

1 file changed

+44
-21
lines changed

1-js/11-async/02-promise-basics/article.md

+44-21
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ That's fine. We immediately have a resolved promise.
127127
The properties `state` and `result` of the Promise object are internal. We can't directly access them. We can use the methods `.then`/`.catch`/`.finally` for that. They are described below.
128128
```
129129
130-
## Consumers: then, catch, finally
130+
## Consumers: then, catch
131131
132-
A Promise object serves as a link between the executor (the "producing code" or "singer") and the consuming functions (the "fans"), which will receive the result or error. Consuming functions can be registered (subscribed) using methods `.then`, `.catch` and `.finally`.
132+
A Promise object serves as a link between the executor (the "producing code" or "singer") and the consuming functions (the "fans"), which will receive the result or error. Consuming functions can be registered (subscribed) using methods `.then` and `.catch`.
133133
134134
### then
135135
@@ -212,59 +212,82 @@ promise.catch(alert); // shows "Error: Whoops!" after 1 second
212212
213213
The call `.catch(f)` is a complete analog of `.then(null, f)`, it's just a shorthand.
214214
215-
### finally
215+
## Cleanup: finally
216216
217217
Just like there's a `finally` clause in a regular `try {...} catch {...}`, there's `finally` in promises.
218218
219-
The call `.finally(f)` is similar to `.then(f, f)` in the sense that `f` always runs when the promise is settled: be it resolve or reject.
219+
The call `.finally(f)` is similar to `.then(f, f)` in the sense that `f` runs always, when the promise is settled: be it resolve or reject.
220220
221-
`finally` is a good handler for performing cleanup, e.g. stopping our loading indicators, as they are not needed anymore, no matter what the outcome is.
221+
The idea of `finally` is to set up a handler for performing cleanup/finalizing after the previous operations are complete.
222222
223-
Like this:
223+
E.g. stopping loading indicators, closing no longer needed connections etc.
224+
225+
Think of it as a party finisher. No matter was a party good or bad, how many friends were in it, we still need (or at least should) do a cleanup after it.
226+
227+
The code may look like this:
224228
225229
```js
226230
new Promise((resolve, reject) => {
227-
/* do something that takes time, and then call resolve/reject */
231+
/* do something that takes time, and then call resolve or maybe reject */
228232
})
229233
*!*
230234
// runs when the promise is settled, doesn't matter successfully or not
231235
.finally(() => stop loading indicator)
232-
// so the loading indicator is always stopped before we process the result/error
236+
// so the loading indicator is always stopped before we go on
233237
*/!*
234238
.then(result => show result, err => show error)
235239
```
236240
237-
That said, `finally(f)` isn't exactly an alias of `then(f,f)` though. There are few subtle differences:
241+
Please note that `finally(f)` isn't exactly an alias of `then(f,f)` though.
242+
243+
There are important differences:
238244
239245
1. A `finally` handler has no arguments. In `finally` we don't know whether the promise is successful or not. That's all right, as our task is usually to perform "general" finalizing procedures.
240-
2. A `finally` handler "passes through" the result or error to the next handler.
246+
247+
Please take a look at the example above: as you can see, the `finally` handler has no arguments, and the promise outcome is handled in the next handler.
248+
2. A `finally` handler "passes through" the result or error to the next suitable handler.
241249
242250
For instance, here the result is passed through `finally` to `then`:
251+
243252
```js run
244253
new Promise((resolve, reject) => {
245-
setTimeout(() => resolve("result"), 2000)
254+
setTimeout(() => resolve("value"), 2000);
246255
})
247-
.finally(() => alert("Promise ready"))
248-
.then(result => alert(result)); // <-- .then handles the result
256+
.finally(() => alert("Promise ready")) // triggers first
257+
.then(result => alert(result)); // <-- .then shows "value"
249258
```
250259
251-
And here there's an error in the promise, passed through `finally` to `catch`:
260+
As you can see, the `value` returned by the first promise is passed through `finally` to the next `then`.
261+
262+
That's very convenient, because `finally` is not meant to process a promise result. As said, it's a place to do generic cleanup, no matter what the outcome was.
263+
264+
And here's an example of an error, for us to see how it's passed through `finally` to `catch`:
252265
253266
```js run
254267
new Promise((resolve, reject) => {
255268
throw new Error("error");
256269
})
257-
.finally(() => alert("Promise ready"))
258-
.catch(err => alert(err)); // <-- .catch handles the error object
270+
.finally(() => alert("Promise ready")) // triggers first
271+
.catch(err => alert(err)); // <-- .catch shows the error
259272
```
260273
261-
That's very convenient, because `finally` is not meant to process a promise result. So it passes it through.
274+
3. A `finally` handler also shouldn't return anything. If it does, the returned value is silently ignored.
275+
276+
The only exception from this rule is when a `finally` handler throws an error. Then this error goes to the next handler, instead of any previous outcome.
262277
263-
We'll talk more about promise chaining and result-passing between handlers in the next chapter.
278+
To summarize:
264279
280+
- A `finally` handler doesn't get the outcome of the previous handler (it has no arguments). This outcome is passed through instead, to the next suitable handler.
281+
- If a `finally` handler returns something, it's ignored. The notable exception is when `finally` throws an error, then the execution goes to a nearest error handler.
282+
283+
That's all fine if we use `finally` the right way, how it's supposed to be used: for generic cleanup procedures.
265284
266285
````smart header="We can attach handlers to settled promises"
267-
If a promise is pending, `.then/catch/finally` handlers wait for it. Otherwise, if a promise has already settled, they just run:
286+
If a promise is pending, `.then/catch/finally` handlers wait for its outcome.
287+
288+
Sometimes, it might be that a promise is already settled when we add a handler to it.
289+
290+
In such case, these handlers just run immediately:
268291
269292
```js run
270293
// the promise becomes resolved immediately upon creation
@@ -278,10 +301,10 @@ Note that this makes promises more powerful than the real life "subscription lis
278301
Promises are more flexible. We can add handlers any time: if the result is already there, they just execute.
279302
````
280303

281-
Next, let's see more practical examples of how promises can help us write asynchronous code.
282-
283304
## Example: loadScript [#loadscript]
284305

306+
Next, let's see more practical examples of how promises can help us write asynchronous code.
307+
285308
We've got the `loadScript` function for loading a script from the previous chapter.
286309

287310
Here's the callback-based variant, just to remind us of it:

0 commit comments

Comments
 (0)