|
1 | 1 | --- |
2 | | -title: Using Signals and Cancellation |
| 2 | +title: Using Cancellation Signals |
3 | 3 | order: 2 |
4 | 4 | --- |
5 | 5 |
|
6 | 6 | Long running tasks, asynchronous tasks, and operations that have a _set up_ and _tear down_ phase, can make use of a |
7 | | -concept called _cancellation_. If you've used other programming languages you might be familiar with objects like |
8 | | -`CancellationToken` (or [Go's `context`](https://pkg.go.dev/context)) - JavaScript's equivalent is `AbortSignal` which |
9 | | -can be operated with an `AbortController`. |
| 7 | +concept called _cancellation signals_. If you've used other programming languages you might be familiar with objects |
| 8 | +like `CancellationToken` (or [Go's `context`](https://pkg.go.dev/context)) - JavaScript's equivalent is `AbortSignal` |
| 9 | +which can be operated with an `AbortController`. |
10 | 10 |
|
11 | 11 | The `AbortController` & `AbortSignal` APIs can help manage operational "life time". Some examples: |
12 | 12 |
|
13 | 13 | - Long running or asynchronous tasks, for example timers or network fetches |
14 | 14 | - Overlapping operations, for example cancelling in-flight network fetches to replace them with newer ones |
15 | 15 | - Set up and tear down, for example a Web Components `connectedCallback` and `disconnectedCallback` |
16 | 16 |
|
17 | | -## Signal Controller Pattern |
| 17 | +## AbortSignal AbortController Pattern |
18 | 18 |
|
19 | | -_Signals_ get given to APIs so they know when to abort. Signals are created by _controllers_ (`new AbortSignal()` will |
20 | | -throw an error). _Controllers_ allow you to make the decision of when a Signal changes. Creating an `AbortController` |
21 | | -will also create a new _Signal_ accessible via `.signal`. Code that has access to the _controller_ can determine when it |
22 | | -should be aborted (by calling `.abort()`), while code that has access to the _signal_ can be notified of the abort. To |
23 | | -make a new `AbortController`, call `new AbortContoller()`. The constructor takes no arguments. |
| 19 | +_Cancellation Signals_ get given to APIs so they know when to abort. An `AbortSignal` is created by a _controller_ |
| 20 | +(`new AbortSignal()` will throw an error). _Controllers_ allow you to make the decision of when a _Cancellation Signal_ |
| 21 | +changes. Creating an `AbortController` will also create a new `AbortSignal`, accessible via `.signal`. Code that has |
| 22 | +access to the _controller_ can determine when it should be aborted (by calling `.abort()`), while code that has access |
| 23 | +to the _signal_ can be notified of the abort. To make a new `AbortController`, call `new AbortContoller()`. The |
| 24 | +constructor takes no arguments. |
24 | 25 |
|
25 | | -A _signals_ `.aborted` property will be `true` if the signal has been aborted - you can periodically check that to stop |
26 | | -any work that is about to be done. `AbortSignal` is also an `EventTarget` - it emits an `abort` event which you can |
| 26 | +An `AbortSignal`s `.aborted` property will be `true` if the signal has been aborted - you can periodically check that to |
| 27 | +stop any work that is about to be done. `AbortSignal` is also an `EventTarget` - it emits an `abort` event which you can |
27 | 28 | listen to and invoke your tear down. |
28 | 29 |
|
29 | 30 | You can also create some basic _controller-free signals_ that follow some common patterns. For example |
30 | | -`AbortSignal.timeout(1000)` will create a _signal_ that aborts after 1000ms. These _controller-free signals_ cannot be |
31 | | -manually aborted. However, you can _combine_ controller-free and controllable signals with |
| 31 | +`AbortSignal.timeout(1000)` will create a _cancellation signal_ that aborts after 1000ms. These _controller-free |
| 32 | +signals_ cannot be manually aborted. However, you can _combine_ controller-free and controllable signals with |
32 | 33 | `AbortSignal.any([...signals])`. |
33 | 34 |
|
34 | | -## Using Signals internally manage your private APIs |
| 35 | +## Using Cancellation Signals internally manage your private APIs |
35 | 36 |
|
36 | | -_Signals_ can be used to manage internal state that you might have. You can create an `AbortController` as part of your |
37 | | -private state, and make use of _signals_ to control behavior. Consumers of your component won't pass these signals to |
38 | | -you, instead you can use them to track a tasks state internally. |
| 37 | +_Cancellation Signals_ can be used to manage internal state that you might have. You can create an `AbortController` as |
| 38 | +part of your private state, and make use of _signals_ to control behavior. Consumers of your component won't pass these |
| 39 | +signals to you, instead you can use them to track a tasks state internally. |
39 | 40 |
|
40 | 41 | A component with `start()` and `stop()` functions can make the `stop()` function abort the controller, and the `start()` |
41 | 42 | function create the controller, while checking if the signal has been aborted during an asynchronous loop like so: |
@@ -82,14 +83,15 @@ class StopWatchElement extends HTMLElement { |
82 | 83 | } |
83 | 84 | ``` |
84 | 85 |
|
85 | | -## Using Signals in your own public APIs |
| 86 | +## Using Cancellation Signals in your own public APIs |
86 | 87 |
|
87 | 88 | If you can use a signal as part of your internal state, it might be simpler to provide it as part of the public API. If |
88 | | -you are considering using _signals_ in a public API, it's a good idea to make them an optional part of your API as they |
89 | | -won't always be _needed_. |
| 89 | +you are considering using _cancellation signals_ in a public API, it's a good idea to make them an optional part of your |
| 90 | +API as they won't always be _needed_. |
90 | 91 |
|
91 | | -A component using _signals_ no longer needs separate start & stop methods, instead combining into one and relying on the |
92 | | -signal to know when to stop. This can often simplify code as there is no need to track state across different methods. |
| 92 | +A component using _cancellation signals_ no longer needs separate start & stop methods, instead combining into one and |
| 93 | +relying on the signal to know when to stop. This can often simplify code as there is no need to track state across |
| 94 | +different methods. |
93 | 95 |
|
94 | 96 | ```js |
95 | 97 | class StopWatchElement extends HTMLElement { |
@@ -120,14 +122,15 @@ class StopWatchElement extends HTMLElement { |
120 | 122 | } |
121 | 123 | ``` |
122 | 124 |
|
123 | | -## Combining multiple Signals |
| 125 | +## Combining multiple Cancellation Signals |
124 | 126 |
|
125 | | -It's possible to combine multiple sources of signals - for example combining internal and external signals to allow for |
126 | | -multiple flavors of API. Two or more signals can be combined into one using `AbortSignal.any()`, which creates a _new |
127 | | -signal_ that aborts when any of the given _signals_ abort. It's similar to `Promise.any()`, but for Signals. |
| 127 | +It's possible to combine multiple sources of _cancellation signals_ - for example combining internal and external |
| 128 | +_cancellation signals_ to allow for multiple flavors of API. Two or more _cancellation signals_ can be combined into one |
| 129 | +using `AbortSignal.any()`, which creates a _new signal_ that aborts when any of the given _cancellation signals_ abort. |
| 130 | +It's similar to `Promise.any()`, but for `AbortSignal`. |
128 | 131 |
|
129 | | -A component can provide the more traditional `start()` and `stop()` APIs, as well allowing signals to be passed via |
130 | | -`start({ signal })`. Making use of internal and external signals, with `AbortSignal.any()`: |
| 132 | +A component can provide the more traditional `start()` and `stop()` APIs, as well allowing _cancellation signals_ to be |
| 133 | +passed via `start({ signal })`. Making use of internal and external _cancellation signals_, with `AbortSignal.any()`: |
131 | 134 |
|
132 | 135 | ```js |
133 | 136 | class StopWatchElement extends HTMLElement { |
@@ -172,7 +175,7 @@ class StopWatchElement extends HTMLElement { |
172 | 175 | } |
173 | 176 | ``` |
174 | 177 |
|
175 | | -### Using Signals to clean up `disconnectedCallback()` |
| 178 | +### Using Cancellation Signals to clean up `disconnectedCallback()` |
176 | 179 |
|
177 | 180 | _Web Components_ that use the `connectedCallback()` lifecycle hook to set things up typically want to tear down those |
178 | 181 | same things in the `disconnectedCallback()`, but this can sometimes get a little unwieldy. Instead of mirroring |
@@ -214,12 +217,12 @@ class StopWatchElement extends HTMLElement { |
214 | 217 | } |
215 | 218 | ``` |
216 | 219 |
|
217 | | -### Using signals to cancel old requests |
| 220 | +### Using Cancellation Signals to cancel old requests |
218 | 221 |
|
219 | 222 | A common task that components might do is turn a user action into a network fetch. For example a search input might |
220 | 223 | query the database every time a character is pressed. If the user types into the input fast enough, old network requests |
221 | 224 | might stay _in-flight_, saturating the network and delaying newer requests from coming in, making the component feel |
222 | | -sluggish. A good way to combat this is to cancel stale requests by using signals: |
| 225 | +sluggish. A good way to combat this is to cancel stale requests by using _cancellation signals_: |
223 | 226 |
|
224 | 227 | ```js |
225 | 228 | class SearchInputElement extends HTMLInputElement { |
|
0 commit comments