minor fixes
This commit is contained in:
parent
0bfebb4b46
commit
2f4747be58
1 changed files with 68 additions and 41 deletions
|
@ -1,13 +1,15 @@
|
|||
|
||||
# Fetch: Abort
|
||||
|
||||
As we know, `fetch` returns a promise. And JavaScript generally has no concept of "aborting" a promise. So how can we abort a `fetch`?
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
The usage is pretty simple:
|
||||
The usage is very straightforward:
|
||||
|
||||
- Step 1: create a controller:
|
||||
## The AbortController object
|
||||
|
||||
Step 1: create a controller:
|
||||
|
||||
```js
|
||||
let controller = new AbortController();
|
||||
|
@ -15,28 +17,44 @@ The usage is pretty simple:
|
|||
|
||||
A controller is an extremely simple object.
|
||||
|
||||
- It has a single method `abort()`, and a single property `signal`.
|
||||
- When `abort()` is called:
|
||||
- `abort` event triggers on `controller.signal`
|
||||
- It has a single method `abort()`,
|
||||
- And a single property `signal` that allows to set event liseners on it.
|
||||
|
||||
When `abort()` is called:
|
||||
- `controller.signal` emits the `"abort"` event.
|
||||
- `controller.signal.aborted` property becomes `true`.
|
||||
|
||||
All parties interested to learn about `abort()` call set listeners on `controller.signal` to track it.
|
||||
Generally, we have two parties in the process:
|
||||
1. The one that performs an cancelable operation, it sets a listener on `controller.signal`.
|
||||
2. The one one that cancels: it calls `controller.abort()` when needed.
|
||||
|
||||
Like this (without `fetch` yet):
|
||||
Here's the full example (without `fetch` yet):
|
||||
|
||||
```js run
|
||||
let controller = new AbortController();
|
||||
let signal = controller.signal;
|
||||
|
||||
// triggers when controller.abort() is called
|
||||
// The party that performs a cancelable operation
|
||||
// gets "signal" object
|
||||
// and sets the listener to trigger when controller.abort() is called
|
||||
signal.addEventListener('abort', () => alert("abort!"));
|
||||
|
||||
// The other party, that cancels (at any point later):
|
||||
controller.abort(); // abort!
|
||||
|
||||
// The event triggers and signal.aborted becomes true
|
||||
alert(signal.aborted); // true
|
||||
```
|
||||
|
||||
- Step 2: pass the `signal` property to `fetch` option:
|
||||
As we can see, `AbortController` is just a means to pass `abort` events when `abort()` is called on it.
|
||||
|
||||
We could implement same kind of event listening in our code on our own, without `AbortController` object at all.
|
||||
|
||||
But what's valuable is that `fetch` knows how to work with `AbortController` object, it's integrated with it.
|
||||
|
||||
## Using with fetch
|
||||
|
||||
To become able to cancel `fetch`, pass the `signal` property of an `AbortController` as a `fetch` option:
|
||||
|
||||
```js
|
||||
let controller = new AbortController();
|
||||
|
@ -45,9 +63,9 @@ The usage is pretty simple:
|
|||
});
|
||||
```
|
||||
|
||||
The `fetch` method knows how to work with `AbortController`, it listens to `abort` on `signal`.
|
||||
The `fetch` method knows how to work with `AbortController`. It will listen to `abort` events on `signal`.
|
||||
|
||||
- Step 3: to abort, call `controller.abort()`:
|
||||
Now, to to abort, call `controller.abort()`:
|
||||
|
||||
```js
|
||||
controller.abort();
|
||||
|
@ -55,7 +73,9 @@ The usage is pretty simple:
|
|||
|
||||
We're done: `fetch` gets the event from `signal` and aborts the request.
|
||||
|
||||
When a fetch is aborted, its promise rejects with an error `AbortError`, so we should handle it, e.g. in `try..catch`:
|
||||
When a fetch is aborted, its promise rejects with an error `AbortError`, so we should handle it, e.g. in `try..catch`.
|
||||
|
||||
Here's the full example with `fetch` aborted after 1 second:
|
||||
|
||||
```js run async
|
||||
// abort in 1 second
|
||||
|
@ -75,15 +95,18 @@ try {
|
|||
}
|
||||
```
|
||||
|
||||
**`AbortController` is scalable, it allows to cancel multiple fetches at once.**
|
||||
## AbortController is scalable
|
||||
|
||||
For instance, here we fetch many `urls` in parallel, and the controller aborts them all:
|
||||
`AbortController` is scalable, it allows to cancel multiple fetches at once.
|
||||
|
||||
Here's a sketch of code that fetches many `urls` in parallel, and uses a single controller to abort them all:
|
||||
|
||||
```js
|
||||
let urls = [...]; // a list of urls to fetch in parallel
|
||||
|
||||
let controller = new AbortController();
|
||||
|
||||
// an array of fetch promises
|
||||
let fetchJobs = urls.map(url => fetch(url, {
|
||||
signal: controller.signal
|
||||
}));
|
||||
|
@ -94,9 +117,9 @@ let results = await Promise.all(fetchJobs);
|
|||
// it aborts all fetches
|
||||
```
|
||||
|
||||
If we have our own asynchronous jobs, different from `fetch`, we can use a single `AbortController` to stop those, together with fetches.
|
||||
If we have our own asynchronous tasks, different from `fetch`, we can use a single `AbortController` to stop those, together with fetches.
|
||||
|
||||
We just need to listen to its `abort` event:
|
||||
We just need to listen to its `abort` event in our tasks:
|
||||
|
||||
```js
|
||||
let urls = [...];
|
||||
|
@ -118,4 +141,8 @@ let results = await Promise.all([...fetchJobs, ourJob]);
|
|||
// it aborts all fetches and ourJob
|
||||
```
|
||||
|
||||
So `AbortController` is not only for `fetch`, it's a universal object to abort asynchronous tasks, and `fetch` has built-in integration with it.
|
||||
## Summary
|
||||
|
||||
- `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`).
|
||||
- `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`.
|
||||
- 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`.
|
Loading…
Add table
Add a link
Reference in a new issue