解决方案的主要原理是使用axios内部的cancelToken去撤回请求。
详细的使用方法可以参考axios官网
关于源码也可以去了解axios源码解析-取消请求
接下来是我自己总结补充的一些使用方法和注意点
axios其他的配置项就先不关注了,我这里用vuex去存储配置cancelToken的值和相关调用方法,重点在于方法的调用,而不是用什么方式。同样可以用全局的window对象或者vue全局对象存储,也可以用模块化的方式配置。
上代码
1.state定义用于存放cancelToken的Map对象。愿意使用数组也可,将修改Map对象的方法改为修改数组的方法即可。
cancelTokenArr: new Map(),//用于axios在跳转页面时批量撤回请求
2.mutations配置用于修改state值的方法
//添加cancel的方法
pushToken (state, payload) {
state.cancelTokenArr.set(payload.uniqueCode,payload.cancelToken)
},
//删除cancel的方法
clearToken(state, payload){
state.cancelTokenArr.delete(payload.uniqueCode)
},
//遍历执行cancel的方法,执行后重置
reqBackAndClearToken (state) {
state.cancelTokenArr.forEach(item => {
item('路由跳转取消上一页的请求')//item为存储的cancel方法,string可传值可不传值。string对应cancelError中的message,可用于区分不同的cancel调用
})
state.cancelTokenArr.clear()
},
3.配置interceptors.request。将每一条的请求存入一个cancelToken 。
注意:
- 此处的配置是在store.js文件中,不同的配置方式调用的方法不同。合理参考,自由使用
- config.data根据自己项目的请求方式去配置,目的是保证key值的唯一性。(例如配置时间戳+url+data+type)(根据自身项目灵活配置)
- config.cancelToken = new axios.CancelToken…(此处必须给config.cancelToken赋值操作,目的是执行cancel方法的时候有效执行!直接调用new axios.CancelToken()获取内部的cancel是无效方法)
- 此处我的if操作是将后面的重复请求直接撤回(浏览器network不会有记录),else操作是将cancelToken收集起来,用于页面跳转时清除还没有完成的请求(此时会有记录标记状态为canceled)。
service.interceptors.request.use(config => {
if(state.cancelTokenArr.get(config.data)){
config.cancelToken = new axios.CancelToken(cancel=>cancel('后面重复的请求在没有成功返回之前直接撤回'))
}else{
config.cancelToken = new axios.CancelToken((cancel) => {
mutations.pushToken(state,{uniqueCode:config.data, cancelToken: cancel})
})
}
}
4.配置interceptors.response。将每一条完成后的请求中的cancelToken从Map对象中移除。
- 此处的response.config.data等于interceptors.request中的config.data
- 将完成后的cancelToken移除
- error需要特殊处理,使用axios.isCancel(error)判断错误类型
service.interceptors.response.use(response => {
const uniqueCode = response.config.data
if (state.cancelTokenArr.get(uniqueCode)) {
mutations.clearToken(state,{uniqueCode})
}
},
error => {
if(axios.isCancel(error)) return new Promise(()=>{})//此处将error状态特殊处理,返回Promise的pending状态,目的是为了中断promise链式执行代码,这样就不会执行后面的then和catch了
return Promise.reject(error)//通用错误处理
})
5.在路由跳转钩子中批量撤回请求。此处配置在main.js中,注意调用方法。
router.beforeEach((to, from, next) => {
store.commit('reqBackAndClearToken')//后续修改需要在每一个next()之前添加
next();
}