在有些场景下可能需要用到取消请求的操作,比如在同一时刻触发多次请求,只保留最新的请求;比如表单提交中关闭页面等行为,本文加少一些常用的触发 Web 请求的方式如何取消。
AbortControllor
AbortController 接口表示一个控制器对象,该对象允许您在需要时中止一个或多个 Web 请求。
AbortController 分别有一个属性 AbortController.signal 和一个方法 AbortController.abort,他们结合起来可以用来终止 Web 请求。
它的使用过程如下:
首先创建一个 AbortController 对象 controller,然后在调用 fetch 时,传入 controller.signal 作为选项,此时控制器和请求被关联在一起,使用控制器的 controller.abort 方法,即刻终止此请求。
const controller = new AbortController(); |
注意,当 controller.abort 被调用时, fetch 返回的 promise 会进入 reject 状态并返回一个名为 AbortError 的 DOMException。
AbortController.signal 搭配 AbortController.abort 还可以用来响应一些取消类的行为:
const controller = new AbortController(); |
注意,AbortControllor 只对浏览器原生的 fetch 生效,在日常开发中经常使用其它的工具如 axios,下一节看一下 axios 怎么取消。
axios 请求取消
axios 提供了 cancelToken 配置项可以用来取消其请求,其使用和 AbortControllor 很相似,看下面的例子:
const cancelToken = axios.CancelToken; |
也可以给 CancelToken 传入一个执行器来执行:
const CancelToken = axios.CancelToken; |
都写到这里了,顺便看看 axios 内部是怎么实现取消的:
首先看 cancelToken 相关的代码:
// lib/adapters/xhr.js |
可以看到当 cancelToken.promise 调用 resolve 时进行了取消,结合它的使用不难猜测 cancelToken.source().cancel 和 传入 CancelToken 的 executor 返回给用户的方法一定用来是 resolve cancelToken.promise 的,接着找相关代码:
// lib/cancel/CancelToken.js |
从上面看出 axios 的第一个示例 cancelToken.source 方法就是是调用了 CancelToken 构造器,也就是上面 axios 示例的第二种写法,后面就没必要看了,继续找构造器相关的代码就知道做了什么:
// lib/cancel/CancelToken.js |
很明显可以看出 this.promise 就是 config.cancelToken.promise.then,而 executor 就是 new CancelToken 时传入的方法,最终暴露给外面了 function cancel 这个方法,而这个方法就是用来 config.cancelToken.promise,和前面的猜测一致,不在多说。
同样的,使用同一个 cancelToken 也可以取消多个请求。
中止 Promise
Promise 也可以手动中止,只需要在创建 Promise 时,对外暴露 reject:
let abort; |
XHR 请求取消
XHR 原生提供了 abort 方法,可以直接取消:
let xhr = new XMLHttpRequest(); |
注意,和其他不同的是,xhr 取消不会触发 error 事件,而是触发 abort 事件。