前端开发过程中通常使用同步方法(loading)来防止此类问题,但架不住产品经理要求交互友好,拒绝遮罩,必须使用异步,以同一个接口频繁请求为例(频繁点击table不同行,触发行点击事件请求接口):假如触发了两次,第一次接口5s返回数据①,第二次1s返回数据②,那么先获取到②赋值到页面,这时①数据接收到了,会覆盖②的数据。
axios中可以使用拦截器统一处理。本文提供的思路就是利用 axios interceptors API
拦截请求,检测是否有多个相同的请求同时处于 pending 状态,如果有就调用 cancel token API
取消重复的请求,只保留最后一次请求。
直接上代码:
1、在axios中声明数组记录标识
let pending = []; //声明一个数组用于存储每个请求的标识
let cancelToken = axios.CancelToken;
let removePending = (config) => {
//查找数组中是否存在相同请求,存在则取消
for(let p in pending){
if(pending[p].u === config.url.split('?')[0] + '&' + config.method) {
pending[p].f(); //执行取消操作
pending.splice(p, 1); //数组移除当前请求
}
}
}
2、在请求前校验拦截
service.interceptors.request.use(config => {
removePending(config); //在一个axios发送前执行校验取消操作
config.cancelToken = new cancelToken((c)=>{// pending存放每一次请求的标识,config.url请求路径,config.params参数,config.method请求方法
pending.push({ u: config.url.split('?')[0] +'&' + config.method, f: c});
});
return config;
}, error => {
pending = [];//清空记录——这里出现错误可能是网络波动造成的,清空 pending 对象
return Promise.reject(error);
})
3、在请求返回后维护 pending
service.interceptors.response.use(
response => {
// 清除当前记录
for(let p in pending){
if(pending[p].u === response.config.url.split('?')[0] + '&' + response.config.method) {
pending.splice(p, 1);
}
}
return response.data
},
error => {
pending = [];//清空记录
return Promise.reject(error)
}
)
Axios拦截器的工作原理请参考官方文档axios中文文档|axios中文网http://www.axios-js.com/zh-cn/docs/