The AbortSignal
interface represents a signal object that allows you to communicate with a DOM request (such as a fetch request) and abort it if required via an AbortController
object.
The AbortSignal
interface represents a signal object that allows you to communicate with a DOM request (such as a fetch request) and abort it if required via an AbortController
object.
The AbortSignal interface may also inherit properties from its parent interface, EventTarget
.
AbortSignal.aborted
Read only
A Boolean that indicates whether the request(s) the signal is communicating with is/are aborted (true
) or not (false
).
AbortSignal.reason
Read only
A JavaScript value providing the abort reason, once the signal has aborted.
AbortSignal.abort()
Returns an AbortSignal
instance that is already set as aborted.
AbortSignal.timeout()
Returns an AbortSignal
instance that will automatically abort after a specified time.
The AbortSignal
interface may also inherit methods from its parent interface, EventTarget
.
AbortSignal.throwIfAborted()
Throws the signal's abort reason
if the signal has been aborted; otherwise it does nothing.
Listen to this event using addEventListener()
or by assigning an event listener to the oneventname
property of this interface.
abort
Invoked when the DOM requests the signal is communicating with is/are aborted. Also available via the onabort
property.
The following snippet shows how we might use a signal to abort downloading a video using the Fetch API.
We first create an abort controller using the AbortController()
constructor, then grab a reference to its associated AbortSignal
object using the AbortController.signal
property.
When the fetch request is initiated, we pass in the AbortSignal
as an option inside the request's options object (the {signal}
below). This associates the signal and controller with the fetch request, and allows us to abort it by calling AbortController.abort()
. Below you can see that the fetch operation is aborted in the second event listener, which triggered when the abort button (abortBtn
) is clicked.
js
const controller = new AbortController(); const signal = controller.signal; const url = "video.mp4"; const downloadBtn = document.querySelector(".download"); const abortBtn = document.querySelector(".abort"); downloadBtn.addEventListener("click", fetchVideo); abortBtn.addEventListener("click", () => { controller.abort(); console.log("Download aborted"); }); function fetchVideo() { fetch(url, { signal }) .then((response) => { console.log("Download complete", response); }) .catch((err) => { console.error(`Download error: ${err.message}`); }); }
Note: When abort()
is called, the fetch()
promise rejects with an "AbortError
" DOMException
.
You can find a full working example on GitHub; you can also see it running live.
If you need to abort the operation on timeout then you can use the static AbortSignal.timeout()
method. This returns an AbortSignal
that will automatically timeout after a certain number of milliseconds.
The code snippet below shows how you would either succeed in downloading a file, or handle a timeout error after 5 seconds. Note that when there is a timeout the fetch()
promise rejects with a "TimeoutError
" DOMException
. This allows code to differentiate between timeouts (for which user notification is probably required), and user aborts.
js
const url = "video.mp4"; try { const res = await fetch(url, { signal: AbortSignal.timeout(5000) }); const result = await res.blob(); // … } catch (err) { if (err.name === "TimeoutError") { console.error("Timeout: It took more than 5 seconds to get the result!"); } else if (err.name === "AbortError") { console.error( "Fetch aborted by user action (browser stop button, closing tab, etc.", ); } else if (err.name === "TypeError") { console.error("AbortSignal.timeout() method is not supported"); } else { // A network error, or some other problem. console.error(`Error: type: ${err.name}, message: ${err.message}`); } }
fetch()
isn't designed to combine multiple signals, so you can't abort a download "directly" due to either of AbortController.abort()
being called or an AbortSignal
timeout (though as in the preceding example, a timeout signal will abort if triggered by inbuilt browser mechanisms like a stop button).
To trigger on multiple signals they must be daisy chained. The code snippet below shows how you might call AbortController.abort()
in the handler for a separate timer.
js
let timeoutId; try { const controller = new AbortController(); timeoutId = setTimeout(() => controller.abort(), 5000); const res = await fetch(url, { signal: controller.signal }); const body = await res.json(); } catch (e) { if (e.name === "AbortError") { // Notify the user of abort. // Note this will never be a timeout error! } else { // A network error, or some other problem. console.log(`Type: ${e.name}, Message: ${e.message}`); } } finally { clearTimeout(timeoutId); }
Note: Unlike when using AbortSignal.timeout()
, there is no way to tell whether the final abort was caused by a timeout.
An API that needs to support aborting can accept an AbortSignal
object, and use its state to trigger abort signal handling when needed.
A Promise
-based API should respond to the abort signal by rejecting any unsettled promise with the AbortSignal
abort reason
. For example, consider the following myCoolPromiseAPI
, which takes a signal and returns a promise. The promise is rejected immediately if the signal is already aborted, or if the abort event is detected. Otherwise it completes normally and then resolves the promise.
js
function myCoolPromiseAPI(/* …, */ { signal }) { return new Promise((resolve, reject) => { // If the signal is already aborted, immediately throw in order to reject the promise. if (signal.aborted) { reject(signal.reason); } // Perform the main purpose of the API // Call resolve(result) when done. // Watch for 'abort' signals signal.addEventListener("abort", () => { // Stop the main operation // Reject the promise with the abort reason. reject(signal.reason); }); }); }
The API might then be used as shown. Note that AbortController.abort()
is called to abort the operation.
js
const controller = new AbortController(); const signal = controller.signal; startSpinner(); myCoolPromiseAPI({ /* …, */ signal }) .then((result) => {}) .catch((err) => { if (err.name === "AbortError") return; showUserErrorMessage(); }) .then(() => stopSpinner()); controller.abort();
APIs that do not return promises might react in a similar manner. In some cases it may make sense to absorb the signal.
Specification |
---|
DOM Standard # interface-AbortSignal |
Desktop | Mobile | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
Chrome | Edge | Firefox | Internet Explorer | Opera | Safari | WebView Android | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | |
AbortSignal |
66 | 16 | 57 | No | 53 | 11.1 | 66 | 66 | 57 | 47 | 11.3 | 9.0 |
abort_event |
66 | 16 | 57 | No | 53 | 11.1 | 66 | 66 | 57 | 47 | 11.3 | 9.0 |
abort_static |
93 | 93 | 88 | No | 79 | 15 | 93 | 93 | 88 | 66 | 15 | 17.0 |
aborted |
66 | 16 | 57 | No | 53 | 11.1 | 66 | 66 | 57 | 47 | 11.3 | 9.0 |
any_static |
116 | 116 | No | No | 102 | No | 116 | 116 | No | No | No | No |
reason |
98 | 98 | 97 | No | 84 | 15.4 | 98 | 98 | 97 | 68 | 15.4 | 18.0 |
throwIfAborted |
100 | 100 | 97 | No | 86 | 15.4 | 100 | 100 | 97 | 69 | 15.4 | 19.0 |
timeout_static |
103 | 103 | 100 | No | 89 | 16 | 103 | 103 | 100 | 71 | 16 | 20.0 |
© 2005–2023 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal