AbortController
核心逻辑是:利用AbortController接口的只读属性signal标记fetch请求;然后在需要取消请求的时候,调用AbortController接口的abort()方法立即取消请求,并抛出一个错误AbortError。
const controller = new AbortController(); const signal = controller.signal; const url = "video.mp4"; const downloadBtn = document.querySelector(".download"); const abortBtn = document.querySelector(".abort"); downloadBtn.addEventListener("click", fetchVideo); abortBtn.addEventListener("click", () => { controller.abort(); console.log("Download aborted"); }); function fetchVideo() { fetch(url, { signal }) .then((response) => { console.log("Download complete", response); }) .catch((err) => { console.error(`Download error: ${err.message}`); }); }
只读属性signal
AbortController接口的只读属性
方法:abort()
AbortController接口的
取消Axios请求
既然 AbortController接口的
abort() 方法可以终止fetch请求、各种响应主体或者流的消耗,那么我们考虑将其和axios结合,来取消axios的请求。
查看axios官网,也给出了相关介绍:
为了便于在项目中使用,我们在对其进行一个简单的封装,示例如下:
//axios配置 function createRequest() { const request = axios.create({ baseURL: "https://geo.datav.aliyun.com", headers: { "Content-Type": "application/json;charset=utf-8", } }) const cachePool = new Map() const encode = (baseURL, method, url, params) => { const str = `${baseURL}_${url}_${method}_${JSON.stringify(params || {})}`; const encoder = new TextEncoder(); //接受一个字符串作为输入,返回一个包含 UTF-8 编码的文本的 Uint8Array const bytes = encoder.encode(str) //使用Base64编码算法进行编码:将一个二进制字符串(例如,将字符串中的每一个字节都视为一个二进制数据字节)编码为 Base64 编码的 ASCII 字符串 const encoded = btoa(String.fromCharCode(...bytes)) return encoded } /** * 对Axios请求实例的config进行编码 * */ const configEncode = (config) => { //获取基本信息 const baseURL = config.baseURL, method = config.method, url = config.url, params = config?.params || config?.data || {}; //返回编码结果 return encode(baseURL, method, url, params); } //请求拦截器 request.interceptors.request.use( (config) => { // 在发送请求之前做些什么 console.log(config) const controller = new AbortController() config.signal = controller.signal //根据config配置信息进行编码 const encodeKey = configEncode(config) console.log("encodeKey:", encodeKey) //判断请求是否存在 if (cachePool.get(encodeKey)) { controller.abort() console.log('cachePool--cancel:', cachePool) } else { cachePool.set(encodeKey, { abort: controller }) console.log('cachePool--set:', cachePool) } return config; }, (error) => { // 对请求错误做些什么 console.log(error); return Promise.reject(error); } ); //响应拦截器 // 添加响应拦截器 request.interceptors.response.use(function (response) { // 2xx 范围内的状态码都会触发该函数。 // 对响应数据做点什么 const encodeKey = configEncode(response.config) console.log('response---:', response, encodeKey) //缓存对象 const cacheItem = cachePool.get(encodeKey) if (cacheItem) { console.log("res-success:删除缓存对象") cachePool.delete(encodeKey) } return response; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数。 // 对响应错误做点什么 console.log('axios-error:', error) if (error.code === "ERR_CANCELED") { //被取消的axios请求 console.warn(`被取消的重复请求~`) } else { //其它错误 return Promise.reject(error); } }); //返回 return request }
接下来做个简单的测试,
const request = createRequest() const getData = () => { return request.get("/areas_v3/bound/420800_full.json", { params: { a: 1 } }) } getData().then(result => { console.log(result) }) getData().then(result => { console.log(result) }) getData().then(result => { console.log(result) })
查看执行结果:连续发送了3次请求,后两个被取消掉,最终只有一个请求正常返回了请求结果。
其它取消Axios请求的方式
参考:Vue:Axios前端拦截器_vue axios拦截器-CSDN博客