基于Ts封装Axios实现取消重复请求

223 阅读1分钟

在axios同级文件夹新建cancel.ts

  • 当进入请求拦截器的时候,调用addPending,调用addPending前,先执行removePedding方法,终止掉请求队列中的请求,pendingMap set当前请求,以method,url参数当做key,valueAbortController实例;
  • 当页面进入响应拦截器的时候,调用remove,清除pendingMap中的当前key
  • 需要注意的是,取消请求后会触发响应拦截器的err回调,所以需要做一下处理。
import type { AxiosRequestConfig } from "axios";

export class AxiosCancel{
    // 用于装载状态处于请求中的axios请求
    pendingMap: Map<string, AbortController>;
    constructor(){
        this.pendingMap = new Map<string, AbortController>();
    }
    // 获取处于pendingMap的key
    generateKey(config:AxiosRequestConfig):string{
        const{method,url}= config;
        return [url||"",method||""].join("&");
    }

    addPending(config:AxiosRequestConfig){
        this.removePending(config);
        const key: string = this.generateKey(config)
        if(!this.pendingMap.has(key)){
            const controller = new AbortController();
            config.signal = controller.signal;
            this.pendingMap.set(key,controller);
        } else{
            config.signal = (this.pendingMap.get(key) as AbortController).signal;
        }
    }

    removePending(config:AxiosRequestConfig){
        const key:string = this.generateKey(config);
        if(this.pendingMap.has(key)){
            (this.pendingMap.get(key) as AbortController).abort();
            this.pendingMap.delete(key)
        }
    }

    removeAllPending(){
        this.pendingMap.forEach((cancel:AbortController)=>{
            cancel.abort();
        });
        this.reset();
    }

    reset(){
        this.pendingMap = new Map<string, AbortController>();
    }
}

在axios中实现调用

import axios, { type AxiosResponse } from "axios";
import { AxiosCancel } from "./cancel"

const axiosCancel = new AxiosCancel()

//axios请求拦截器
httpInstance.interceptors.request.use(config => {
    ...
    axiosCancel.addPending(config);
    return config
}, e => Promise.reject(e))

//axios响应式拦截器
httpInstance.interceptors.response.use((res: AxiosResponse) => {
    // ...其他代码
    axiosCancel.removePending(res.config);
}, err => {
    if (err.code === "ERR_CANCELED") return;
    // ...其他代码
    axiosCancel.removePending(err.config || {});
})