目前,浏览器端原生获取数据,发请求的主要是
XMLHttpRequest 和 fetch,XMLHttpRequest 作为元老级的存在, fetch 是在 ES6 中推出的更现代的 API。XMLHttpRequest 本身是支持请求中断的(abort),以下是 XHR 中断的示例const xhr = new XMLHttpRequest() xhr.method = 'GET' xhr.url = 'https://slowmo.glitch.me/5000' xhr.open(method, url, true) xhr.send() // 中断请求 abortButton.addEventListener('click', () => xhr.abort())
什么是 AbortController?
正如 DOM 规范文档中所说
Though promises do not have a built-in aborting mechanism, many APIs using them require abort semantics. AbortController is meant to support these requirements by providing an abort() method that toggles the state of a corresponding AbortSignal object. The API which wishes to support aborting can accept an AbortSignal object, and use its state to determine how to proceed.
以下是
AbortController 的基本用法// 创建 AbortController 的实例 const controller = new AbortController() const signal = controller.signal // 监听 abort 事件,在 controller.abort() 执行后执行回调打印 signal.addEventListener('abort', () => { console.log(signal.aborted) // true }) // 触发中断 controller.abort()
使用 AbortController 中断 fetch 请求
const controller = new AbortController() const signal = controller.signal // API 5s 后返回相应 // https://slowmo.glitch.me/5000 5000 代表 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.log('Error', err) } }) // 在 2s 后中断请求,将触发 'AbortError' setTimeout(() => controller.abort(), 2000)
需要注意的是已经abort的请求是不能重复调用的。
AbortSignal 在 abort 之后,状态就变成了 aborted,那么下次调用 fetch 请求的时候,当读到 AbortSignal 的状态是 aborted 的时候,就直接 reject 。
如果需要重新发起请求,我们就需要用新的controller来控制,不然上一次请求会直接reject
利用AbortController废弃监听器addEventListener事件
按照MDN文档-addEventListener,AbortController还可以作为addEventListener第三个参数options上的可选属性。当调用abort()后,监听器会被移除。其实这就相当于给我们内置了一个移除监听器的方式,可以不用把callback单独提取出成一个函数。
const controller = new AbortController(); function callback (e) { document.addEventListener('mousemove', (e) => { },{ signal: controller.signal }); } document.addEventListener('mousedown', callback); document.addEventListener('mouseup', controller.abort);