Skip to content

Commit 2f4747b

Browse files
committed
minor fixes
1 parent 0bfebb4 commit 2f4747b

File tree

1 file changed

+68
-41
lines changed

1 file changed

+68
-41
lines changed

Diff for: 5-network/04-fetch-abort/article.md

+68-41
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,81 @@
11

22
# Fetch: Abort
33

4-
As we know, `fetch` returns a promise. And JavaScript generally has no concept of "aborting" a promise. So how can we abort a `fetch`?
4+
As we know, `fetch` returns a promise. And JavaScript generally has no concept of "aborting" a promise. So how can we cancel an ongoing `fetch`? E.g. if the user actions on our site indicate that the `fetch` isn't needed any more.
55

6-
There's a special built-in object for such purposes: `AbortController`, that can be used to abort not only `fetch`, but other asynchronous tasks as well.
6+
There's a special built-in object for such purposes: `AbortController`. It can be used to abort not only `fetch`, but other asynchronous tasks as well.
77

8-
The usage is pretty simple:
8+
The usage is very straightforward:
99

10-
- Step 1: create a controller:
10+
## The AbortController object
1111

12-
```js
13-
let controller = new AbortController();
14-
```
12+
Step 1: create a controller:
1513

16-
A controller is an extremely simple object.
14+
```js
15+
let controller = new AbortController();
16+
```
1717

18-
- It has a single method `abort()`, and a single property `signal`.
19-
- When `abort()` is called:
20-
- `abort` event triggers on `controller.signal`
21-
- `controller.signal.aborted` property becomes `true`.
18+
A controller is an extremely simple object.
2219

23-
All parties interested to learn about `abort()` call set listeners on `controller.signal` to track it.
20+
- It has a single method `abort()`,
21+
- And a single property `signal` that allows to set event liseners on it.
2422

25-
Like this (without `fetch` yet):
23+
When `abort()` is called:
24+
- `controller.signal` emits the `"abort"` event.
25+
- `controller.signal.aborted` property becomes `true`.
2626

27-
```js run
28-
let controller = new AbortController();
29-
let signal = controller.signal;
27+
Generally, we have two parties in the process:
28+
1. The one that performs an cancelable operation, it sets a listener on `controller.signal`.
29+
2. The one one that cancels: it calls `controller.abort()` when needed.
3030

31-
// triggers when controller.abort() is called
32-
signal.addEventListener('abort', () => alert("abort!"));
31+
Here's the full example (without `fetch` yet):
3332

34-
controller.abort(); // abort!
33+
```js run
34+
let controller = new AbortController();
35+
let signal = controller.signal;
36+
37+
// The party that performs a cancelable operation
38+
// gets "signal" object
39+
// and sets the listener to trigger when controller.abort() is called
40+
signal.addEventListener('abort', () => alert("abort!"));
3541

36-
alert(signal.aborted); // true
37-
```
42+
// The other party, that cancels (at any point later):
43+
controller.abort(); // abort!
3844

39-
- Step 2: pass the `signal` property to `fetch` option:
45+
// The event triggers and signal.aborted becomes true
46+
alert(signal.aborted); // true
47+
```
4048

41-
```js
42-
let controller = new AbortController();
43-
fetch(url, {
44-
signal: controller.signal
45-
});
46-
```
49+
As we can see, `AbortController` is just a means to pass `abort` events when `abort()` is called on it.
4750

48-
The `fetch` method knows how to work with `AbortController`, it listens to `abort` on `signal`.
51+
We could implement same kind of event listening in our code on our own, without `AbortController` object at all.
4952

50-
- Step 3: to abort, call `controller.abort()`:
53+
But what's valuable is that `fetch` knows how to work with `AbortController` object, it's integrated with it.
5154

52-
```js
53-
controller.abort();
54-
```
55+
## Using with fetch
5556

56-
We're done: `fetch` gets the event from `signal` and aborts the request.
57+
To become able to cancel `fetch`, pass the `signal` property of an `AbortController` as a `fetch` option:
5758

58-
When a fetch is aborted, its promise rejects with an error `AbortError`, so we should handle it, e.g. in `try..catch`:
59+
```js
60+
let controller = new AbortController();
61+
fetch(url, {
62+
signal: controller.signal
63+
});
64+
```
65+
66+
The `fetch` method knows how to work with `AbortController`. It will listen to `abort` events on `signal`.
67+
68+
Now, to to abort, call `controller.abort()`:
69+
70+
```js
71+
controller.abort();
72+
```
73+
74+
We're done: `fetch` gets the event from `signal` and aborts the request.
75+
76+
When a fetch is aborted, its promise rejects with an error `AbortError`, so we should handle it, e.g. in `try..catch`.
77+
78+
Here's the full example with `fetch` aborted after 1 second:
5979

6080
```js run async
6181
// abort in 1 second
@@ -75,15 +95,18 @@ try {
7595
}
7696
```
7797

78-
**`AbortController` is scalable, it allows to cancel multiple fetches at once.**
98+
## AbortController is scalable
7999

80-
For instance, here we fetch many `urls` in parallel, and the controller aborts them all:
100+
`AbortController` is scalable, it allows to cancel multiple fetches at once.
101+
102+
Here's a sketch of code that fetches many `urls` in parallel, and uses a single controller to abort them all:
81103

82104
```js
83105
let urls = [...]; // a list of urls to fetch in parallel
84106

85107
let controller = new AbortController();
86108

109+
// an array of fetch promises
87110
let fetchJobs = urls.map(url => fetch(url, {
88111
signal: controller.signal
89112
}));
@@ -94,9 +117,9 @@ let results = await Promise.all(fetchJobs);
94117
// it aborts all fetches
95118
```
96119

97-
If we have our own asynchronous jobs, different from `fetch`, we can use a single `AbortController` to stop those, together with fetches.
120+
If we have our own asynchronous tasks, different from `fetch`, we can use a single `AbortController` to stop those, together with fetches.
98121

99-
We just need to listen to its `abort` event:
122+
We just need to listen to its `abort` event in our tasks:
100123

101124
```js
102125
let urls = [...];
@@ -118,4 +141,8 @@ let results = await Promise.all([...fetchJobs, ourJob]);
118141
// it aborts all fetches and ourJob
119142
```
120143

121-
So `AbortController` is not only for `fetch`, it's a universal object to abort asynchronous tasks, and `fetch` has built-in integration with it.
144+
## Summary
145+
146+
- `AbortController` is a simple object that generates `abort` event on it's `signal` property when `abort()` method is called (and also sets `signal.aborted` to `true`).
147+
- `fetch` integrates with it: we pass `signal` property as the option, and then `fetch` listens to it, so it becomes possible to abort the `fetch`.
148+
- We can use `AbortController` in our code. The "call `abort()`" -> "listen to `abort` event" interaction is simple and universal. We can use it even without `fetch`.

0 commit comments

Comments
 (0)