AbortSignal
Baseline 广泛可用 *
注意:此功能在 Web Workers 中可用。
AbortSignal 接口表示一个信号对象,允许您与异步操作(如 fetch 请求)进行通信,并通过 AbortController 对象在需要时中止该操作。
实例属性
还继承了其父接口 EventTarget 的属性。
AbortSignal.aborted只读-
一个 布尔值,指示信号正在通信的请求是否已被中止(
true)或未被中止(false)。 AbortSignal.reason只读-
信号中止后,提供中止原因的 JavaScript 值。
静态方法
还继承了其父接口 EventTarget 的方法。
AbortSignal.abort()-
返回一个已设置为已中止的
AbortSignal实例。 AbortSignal.any()-
返回一个
AbortSignal,当给定的任何中止信号中止时,它将中止。 AbortSignal.timeout()-
返回一个
AbortSignal实例,该实例将在指定时间后自动中止。
实例方法
还继承了其父接口 EventTarget 的方法。
AbortSignal.throwIfAborted()-
如果信号已被中止,则抛出信号的中止
reason;否则不执行任何操作。
事件
还继承了其父接口 EventTarget 的事件。
使用 addEventListener() 侦听此事件,或将事件监听器分配给此接口的 oneventname 属性。
abort-
当信号正在通信的异步操作被中止时调用。也可通过
onabort属性访问。
示例
使用显式信号中止 fetch 操作
以下代码片段展示了如何使用信号通过 Fetch API 中止视频下载。
我们首先定义一个 AbortController 变量。
在每个 fetch 请求之前,我们使用 AbortController() 构造函数创建一个新的控制器,然后通过 AbortController.signal 属性获取对其关联 AbortSignal 对象的引用。
注意: 一个 AbortSignal 只能使用一次。一旦它被中止,任何使用相同信号的 fetch 调用都将立即被拒绝。
当 fetch 请求被发起时,我们将 AbortSignal 作为请求选项对象中的一个选项(下面的 { signal })传入。这会将信号和控制器与 fetch 请求关联起来,并通过调用 AbortController.abort() 来中止它,正如下面的第二个事件监听器中所见。
当调用 abort() 时,fetch() Promise 会以一个名为 AbortError 的 DOMException 被拒绝。
let controller;
const url = "video.mp4";
const downloadBtn = document.querySelector(".download");
const abortBtn = document.querySelector(".abort");
downloadBtn.addEventListener("click", fetchVideo);
abortBtn.addEventListener("click", () => {
if (controller) {
controller.abort();
console.log("Download aborted");
}
});
async function fetchVideo() {
controller = new AbortController();
const signal = controller.signal;
try {
const response = await fetch(url, { signal });
console.log("Download complete", response);
// process response further
} catch (err) {
console.error(`Download error: ${err.message}`);
}
}
如果请求在 fetch() 调用已完成但响应体尚未读取之前被中止,那么尝试读取响应体会因 AbortError 异常而被拒绝。
async function get() {
const controller = new AbortController();
const request = new Request("https://example.org/get", {
signal: controller.signal,
});
const response = await fetch(request);
controller.abort();
// The next line will throw `AbortError`
const text = await response.text();
console.log(text);
}
您可以在 GitHub 上找到完整的可运行示例;您也可以 在线查看。
使用超时中止 fetch 操作
如果您需要在超时时中止操作,可以使用静态的 AbortSignal.timeout() 方法。它返回一个 AbortSignal,该信号将在指定毫秒数后自动超时。
以下代码片段展示了如何成功下载文件,或在 5 秒后处理超时错误。请注意,当发生超时时,fetch() Promise 会以一个 TimeoutError DOMException 被拒绝。这使得代码可以区分超时(可能需要用户通知)和用户中止。
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 {
// A network error, or some other problem.
console.error(`Error: type: ${err.name}, message: ${err.message}`);
}
}
使用超时或显式中止来中止 fetch
如果您想从多个信号中中止,可以使用 AbortSignal.any() 将它们合并成一个信号。以下示例使用 fetch 展示了这一点。
try {
const controller = new AbortController();
const timeoutSignal = AbortSignal.timeout(5000);
const res = await fetch(url, {
// This will abort the fetch when either signal is aborted
signal: AbortSignal.any([controller.signal, timeoutSignal]),
});
const body = await res.json();
} catch (e) {
if (e.name === "AbortError") {
// Notify the user of abort.
} else if (e.name === "TimeoutError") {
// Notify the user of timeout
} else {
// A network error, or some other problem.
console.log(`Type: ${e.name}, Message: ${e.message}`);
}
}
注意: 与使用 AbortSignal.timeout() 不同,无法确定最终的中止是由超时引起的。
实现可中止的 API
需要支持中止的 API 可以接受一个 AbortSignal 对象,并利用其状态在需要时触发中止信号处理。
基于 Promise 的 API 应该通过用 AbortSignal 的中止 reason 来拒绝任何尚未解决的 Promise 来响应中止信号。例如,考虑以下 myCoolPromiseAPI,它接受一个信号并返回一个 Promise。如果信号已被中止,或者检测到中止事件,Promise 会立即被拒绝。否则,它会正常完成,然后解析 Promise。
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);
return;
}
// 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);
});
});
}
API 随后可以像这样使用。请注意,AbortController.abort() 被调用来中止操作。
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();
不返回 Promise 的 API 可能会以类似的方式做出反应。在某些情况下,吸收信号可能是有意义的。
规范
| 规范 |
|---|
| DOM # interface-AbortSignal |
浏览器兼容性
加载中…
另见
- Fetch API
- Jake Archibald 的 可中止的 Fetch