Axios取消请求:AbortController

AbortController

AbortController() 构造函数创建了一个新的 AbortController 实例。MDN官网给出了一个利用AbortController取消下载视频的例子。

核心逻辑是:利用AbortController接口的只读属性signal标记fetch请求;然后在需要取消请求的时候,调用AbortController接口的abort()方法立即取消请求,并抛出一个错误AbortError。

javascript 复制代码
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接口的只读属性 signal 返回一个 AbortSignal 实例对象,该对象可以根据需要处理 DOM 请求通信,既可以建立通信,也可以终止通信。

方法:abort()

AbortController接口的 abort() 方法会在 DOM 请求完成之前中止它。它能够中止 fetch 请求、各种响应主体或者流的消耗。

取消Axios请求

既然 AbortController接口的 abort() 方法可以终止fetch请求、各种响应主体或者流的消耗,那么我们考虑将其和axios结合,来取消axios的请求。

查看axios官网,也给出了相关介绍:

为了便于在项目中使用,我们在对其进行一个简单的封装,示例如下:

javascript 复制代码
//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
        }

接下来做个简单的测试,

javascript 复制代码
        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博客

相关推荐
不会敲代码11 小时前
手写 Mini React:从 JSX 到虚拟 DOM 再到 render,搞懂 React 底层原理
前端·javascript·react.js
你不是我我2 小时前
【Java 开发日记】HTTP3 性能更好,为什么内网微服务依然多用 HTTP2?HTTP2 内网优势是什么?
java·开发语言·微服务
kyriewen2 小时前
你的代码仓库变成“毛线团”了?Monorepo 用 Turborepo 拆成“乐高积木”
前端·javascript·面试
身如柳絮随风扬2 小时前
你知道什么是 Ajax 吗?—— 从入门到原理,一篇彻底搞懂
前端·ajax·okhttp
tjl521314_213 小时前
04C++ 名称空间(Namespace)
开发语言·c++
赏金术士3 小时前
Kotlin 数据流与单双向绑定
android·开发语言·kotlin
旷世奇才李先生3 小时前
Vue3\+TypeScript 2026实战——企业级前端项目架构搭建与性能优化全指南
前端·架构·typescript
Beginner x_u3 小时前
前端八股整理(工程化 02)|CommonJS/ESM、Webpack Loader/Plugin 与Vite 对比
前端·webpack·node.js·plugin·loader
逻辑驱动的ken4 小时前
Java高频面试场景题25
java·开发语言·深度学习·面试·职场和发展
openKaka_4 小时前
createRoot 到底创建了什么:FiberRootNode 和 HostRootFiber 的初始化过程
前端·javascript·react.js