在axios同级文件夹新建cancel.ts
- 当进入请求拦截器的时候,调用
addPending,调用addPending前,先执行removePedding方法,终止掉请求队列中的请求,pendingMap set当前请求,以method,url参数当做key,value为AbortController实例;
- 当页面进入响应拦截器的时候,调用
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 || {});
})