如何终止Fetch请求
到目前为止,在浏览器里用 JavaScript 发起请求的方式有两种:XMLHttpRequest 和 fetch。XMLHttpRequest 我们比较熟悉,存在很长时间了,而 fetch 是 ES6 才引入的。
XMLHttpRequest 是可以中途取消的,如下所示:
let xhr = new XMLHttpRequest();
xhr.method = 'GET';
xhr.url = 'https://slowmo.glitch.me/5000';
xhr.open(method, url, true);
xhr.send();
// 随后取消这个请求
abortButton.addEventListener('click', function() {
xhr.abort();
});
fetch 刚开始引入的时候并不支持终止操作。最早的关于终止 fetch 请求的 GitHub issue 是在 2015 年提出的。在 fetch 规范之外,有不少解决这个问题的尝试,比如 cancelable-promises 和其他 hacks 手段。
但是现在我们终于有了通用的AbortController 和 AbortSignal API。这些 API 是由 DOM 标准而不是语言本身提供的。
AbortController 是何方神圣
AbortController
DOM 规范文档 是这样描述的:
虽然 promise 没有内置的中断机制,很多使用它的 API 需要这个中止语义。AbortController就是通过提供abort() 方法切换相应 AbortSignal 对象的状态,从而满足这种需求的。想要支持终止功能的 API 可以接受一个AbortSignal 对象,然后根据它的状态决定如何继续。
// 创建 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;
// 监听 abort 信号, controller.abort() 执行时触发回调
signal.addEventListener('abort', () => {
console.log(signal.aborted); // true
});
// 稍后调用终止方法,发出信号
controller.abort();
如何通过 AbortController 终止 fetch 请求?
fetch 接受 AbortSignal作为第二个参数的一部分。
const controller = new AbortController();
const signal = controller.signal;
// 5s 后请求收到响应,注意第二个参数
fetch('https://slowmo.glitch.me/5000', { signal })
.then(r => r.json())
.then(response => console.log(response))
.catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch was aborted');
} else {
console.error('Oops!', err);
}
});
// 2秒后取消请求
setTimeout(() => {
controller.abort();
}, 2000);
终止 fetch 会同时终止请求和响应,并抛出new DOMException('Aborted', 'AbortError')错误。另外,同一个 AbortSignal对象(上例中的signal)可以用于取消多个fetch请求。
发表评论 (审核通过后显示评论):