技术环境,vue + ts + antd vue
弹窗modal的确认按钮往往伴随着保存类接口的调用,但是ui框架是不会自带连点debounce的。
要是编辑的那倒没啥问题,多保存几次也不会出问题,但要是新增,一次性push多次问题就大了。因为是公司内部的管理系统,不对外,本着自己人凑活着用的态度,这个问题从项目之初就没人在意。实在扛不住产品某些特殊场景有需要就用防抖节流混过去。
好在最近项目不紧急,我就想把这个问题从根本性的解决了,
用我们领导的一句话叫:造钟而不是报时
查阅了一下网上的资料,baidu前几条讲的都是axios 的cancelToken的妙用,但是通篇看下来后我发现这不符合我的需求。因为cancelToken只是前端主动把http中止了,但是后端已经接收到了请求并且新增了数据,前端看到的确实是一串请求前面的都红色取消了只有最后一个200成功,但是多余的数据还是产生了,所以我并没有采用cancelToken。
工具函数
const pendingRequest = new Set(); // 定义一个用于存储正在调用接口的列表
// 以下因为项目比较简单所以没有用到config的method,url,params,data去qs序列化一个键名
// 非restful的接口请求,我觉得只用url作为键基本够用
// push列表
function addPendingRequest(config) {
pendingRequest.add(config.url);
}
// pop列表
function removePendingRequest(config) {
const requestKey = config.url;
if (pendingRequest.has(requestKey)) {
pendingRequest.delete(requestKey);
}
}
// 中止本次请求
function removeCurrentRequest(config) {
const requestKey = config.url;
if (pendingRequest.has(requestKey)) {
throw new Error(requestKey + '请求重复');
}
}
请求拦截器代码
// 请求之前的拦截器
const requestInterceptor = (config: AxiosRequestConfig) => {
removeCurrentRequest(config); // 存在则取消当前的请求
addPendingRequest(config); // push
//...你的config配置
return config;
}
// 请求之前的拦截器错误处理
const requestInterceptorCatch = (error: Error) => {
Promise.reject(error);
};
相应拦截代码
// 请求之后的拦截器
const responseInterceptor = (response: AxiosResponse) => {
removePendingRequest(response.config); // pop
// 你的response配置...
return Promise.resolve(response.data)
或者Promise.reject(new Error('error'))
}
// 请求之后的拦截器错误处理
const responseInterceptorCatch = (error: any) => {
removePendingRequest(error.config || {}); // pop
return Promise.reject(error);
};
装载之前写的拦截器代码
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
const service = axios.create({...})
...
service.interceptors.request.use(requestInterceptor, requestInterceptorCatch);
service.interceptors.response.use(responseInterceptor, responseInterceptorCatch);
export default service;