if (!pending.has(url)) { // 如果 pending 中不存在当前请求,则添加进去
pending.set(url, cancel)
}
})
}
/**
* 移除请求
* @param {Object} config
*/
const removePending = (config) => {
const url = [
config.method,
config.url,
qs.stringify(config.params),
qs.stringify(config.data)
].join('&')
if (pending.has(url)) { // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
const cancel = pending.get(url)
cancel(url)
pending.delete(url)
}
}
/**
* 清空 pending 中的请求(在路由跳转时调用)
*/
export const clearPending = () => {
for (const [url, cancel] of pending) {
cancel(url)
}
pending.clear()
}
Map是ES6中一种新型的数据结构,本身提供了诸多方法,方便操作,适合当前场景。如果不熟悉的可以查看ECMAScript 6 入门。
在给config.cancelToken赋值的时候,需要判断当前请求是否已经在业务代码中使用了cancelToken
qs是一个专门用来转换对象和字符串参数的库,最初是由 TJ 创建并维护的,也是axios推荐使用的参数序列化库。这里我们的目的只是单纯的将参数对象转换为字符串方便拼接。
Map结构默认部署了Symbol.iterator属性,可以使用for…of循环直接获取键名和键值,当然你也可以使用for…in循环。
在 axios 拦截器中使用
主要的方法已经写好了,只需要添加到axios拦截器中就可以了。
axios.interceptors.request.use(config => {
removePending(options) // 在请求开始前,对之前的请求做检查取消操作
addPending(options) // 将当前请求添加到 pending 中
// other code before request
return config
}, error => {
return Promise.reject(error)
})axios.interceptors.response.use(response => {
removePending(response) // 在请求结束后,移除本次请求
return response
}, error => {
if (axios.isCancel(error)) {
console.log('repeated request: ' + error.message)
} else {
// handle error code
}
return Promise.reject(error)
})
将clearPending()方法添加到vue路由钩子函数中
router.beforeEach((to, from, next) => {
clearPending()
// ...
next()
})测试效果
最后我们可以在浏览器中测试下,可以将chrome中控制面板的Network的网络状态切换为Slow 3G来模拟网速慢的情况。
我们把查询按钮的loading或者disabled属性干掉来方便测试

在上面控制面板中可以看到,红色的status为canceled的就是被取消的请求。










