背景
这是个后台系统, 可以频繁点击按钮,触发请求。由于类似的场景还很多例如不同用户在较短时间间隔内变更数据,或者某一个用户进行的重复提交操作都可能导致并发冲突。
对于这类问题可一般采取的方式:
-
找到按钮 每次发请求添加 loading
这是最直接有效的方式,如果你们前端团队成员足够细心耐心,拥有良好的编码习惯,这样就可以解决大部分用户不小心重复提交带来的并发问题了。 -
全局loading
根据请求状态设置加载状态,页面级loading , 可能会造成重复的loading -
axios 拦截器统一处理
由于需要限制的场景多, 项目也复杂, 从根本上进行控制, 发现连续的重复请求取消掉, 保留最新的,统一处理重复请求实现自动拦截,就可以大大简化我们的业务代码。
实现
- 在 interceptors 请求拦截器中创建存放请求的 map 对象, 对象的key 为 url+data+method
- 每次请求前先检差对象中是否有相同的地址, 有就运行取消请求并删除, 没有则添加 value 为CancelToken 方法
- 在 response 响应失败或成功都要及时清除对象中相应的key
const pendingList = new Map()
export function addCancelToken(axiosConfig) {
let cancel
let id = `${axiosConfig.url}/${JSON.stringify(axiosConfig.params)}/${JSON.stringify(
axiosConfig.data
)}&request_type=${axiosConfig.method}`
const cancelToken = new axios.CancelToken(function executor(c) {
cancel = c
})
axiosConfig.cancelToken = cancelToken
axiosConfig.cancelTokenId = id
// 检查是否有重复请求
removeCancelToken(axiosConfig)
// 存入请求地址,和取消请求方法
if (!pendingList.has(id)) {
pendingList.set(id, () => {
cancel('ctrlCancelToken') // 传参标识, 不弹出错误提示,如果修改参数注意axios
})
}
return pendingList
}
// 取消重复请求 和 删除请求的key
function removeCancelTokenById(id, needCallCancel = false) {
if (pendingList.has(id)) {
pendingList.get(id)()
pendingList.delete(id)
}
}
axios 使用
// 请求拦截器配置处理
this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
// loading 开启
globalLoading.value = true
// 添加 cancelToken 并保存到 config
addCancelToken(config)
})
// 响应结果拦截器处理
this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
globalLoading.value = false
/** 请求成功,将 cancelToken 移除 */
removeCancelToken(res.config)
)}
![](https://img.haomeiwen.com/i2639854/7afe6fd62005c6b9.png)
重复点击只有最后一次生效
总结
axios 取消重复请求这快网上有很多, 思路大都一样。本文主要是让自己,通过某个功能对自己代码进行review和重实现来提高代码质量,希望各位大佬多多指点
网友评论