AbortSignal
注意:此功能在 Web 工作线程 中可用。
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()
构造函数创建一个中止控制器,然后使用 AbortController.signal
属性获取对其关联的 AbortSignal
对象的引用。
当 fetch 请求 初始化时,我们在请求的选项对象(下面的 {signal}
)中将 AbortSignal
作为选项传递。这将信号和控制器与 fetch 请求相关联,并允许我们通过调用 AbortController.abort()
来中止它。在下面,您可以看到 fetch 操作在第二个事件监听器中中止,该监听器在单击中止按钮 (abortBtn
) 时触发。
当调用 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 应该通过拒绝任何未解决的 promise 并使用 AbortSignal
中止 reason
来响应中止信号。例如,考虑以下 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);
}
// 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 |
浏览器兼容性
BCD 表仅在浏览器中加载
另请参阅
- Fetch API
- 可中止的 Fetch 由 Jake Archibald 撰写