大家肯定遇到过这样类似的场景:多个 Tab 页点击切换功能,如果用户点击频繁,很可能会出现当前页面显示别的页面的数据。
因为每个接口返回信息的时间是不同的,你不能保证先请求的一定最先返回数据,那么就很可能会出现停留在页面一却出现别的页面的数据的情况。这种异步的情况术语称之为异步竞态。
axios 如何取消请求
第一种方法
通过axios.CancelToken.source生成取消令牌token和取消方法cancel
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求 (消息参数是可选的)
source.cancel('Operation canceled by the user.');
第二种方式
通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
封装axios
我们利用第二种来封装取消axios请求
原理:一个数组把每一次的请求保存起来 请求成功去掉这个请求 再次发起请求遍历这个数组 看下有没有同样的请求 有同样的 就将上次的请求cancel掉
第一,
let pending = []; //声明一个数组用于存储每个ajax请求的取消函数和ajax标识
let cancelToken = axios.CancelToken;
let removePending = (ever) => {
for(let p in pending){
if(pending[p].u === ever.url + '&' + ever.method) { //当当前请求在数组中存在时执行函数体
pending[p].f(); //执行取消操作
pending.splice(p, 1); //把这条记录从数组中移除
}
}
}
第二,在请求拦截器中
// axios请求拦截
axios.interceptors.request.use(
config=>{
// ------------------------------------------------------------------------------------
removePending(config); //在一个ajax发送前执行一下取消操作
config.cancelToken = new cancelToken((c)=>{
// 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
pending.push({ u: config.url + '&' + config.method, f: c });
});
// -----------------------------------------------------------------------------------------
return config;
},
error => {
return Promise.reject(error);
}
)
第三,响应拦截器
// axios响应拦截
axios.interceptors.response.use(
(config) => {
console.log("config---",config,pending)
// ------------------------------------------------------------------------------------------
removePending(config.config); //在一个ajax响应后再执行一下取消操作,把已经完成的请求从pending中移除
// ------------------------------------------------------------------------------------------
// if (config.data.code != "200" && config.config.responseType !== "blob") {
// Message.warning(config.data.data || config.data.mesg || '')
// }
return config;
},
error => { // error
let msgText = JSON.stringify(error).includes('404')
? 'API Not Found'
: JSON.stringify(error).includes('401')
? '无访问权限, 请联系管理员!'
: 'Internal Server Error';
Message.error(msgText)
return Promise.reject(error) //接口500抛出异常(不走页面逻辑)
}
);
``