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
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.
5
5
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.
7
7
8
-
The usage is pretty simple:
8
+
The usage is very straightforward:
9
9
10
-
- Step 1: create a controller:
10
+
## The AbortController object
11
11
12
-
```js
13
-
let controller =newAbortController();
14
-
```
12
+
Step 1: create a controller:
15
13
16
-
A controller is an extremely simple object.
14
+
```js
15
+
let controller =newAbortController();
16
+
```
17
17
18
-
- It has a single method `abort()`, and a single property `signal`.
// The other party, that cancels (at any point later):
43
+
controller.abort(); // abort!
38
44
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
+
```
40
48
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.
47
50
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.
49
52
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.
51
54
52
-
```js
53
-
controller.abort();
54
-
```
55
+
## Using with fetch
55
56
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:
57
58
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 =newAbortController();
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:
59
79
60
80
```js run async
61
81
// abort in 1 second
@@ -75,15 +95,18 @@ try {
75
95
}
76
96
```
77
97
78
-
**`AbortController` is scalable, it allows to cancel multiple fetches at once.**
98
+
## AbortController is scalable
79
99
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:
81
103
82
104
```js
83
105
let urls = [...]; // a list of urls to fetch in parallel
84
106
85
107
let controller =newAbortController();
86
108
109
+
// an array of fetch promises
87
110
let fetchJobs =urls.map(url=>fetch(url, {
88
111
signal:controller.signal
89
112
}));
@@ -94,9 +117,9 @@ let results = await Promise.all(fetchJobs);
94
117
// it aborts all fetches
95
118
```
96
119
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.
98
121
99
-
We just need to listen to its `abort` event:
122
+
We just need to listen to its `abort` event in our tasks:
100
123
101
124
```js
102
125
let urls = [...];
@@ -118,4 +141,8 @@ let results = await Promise.all([...fetchJobs, ourJob]);
118
141
// it aborts all fetches and ourJob
119
142
```
120
143
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