前言
关于取消重复请求,最重要的是这么做的意义,而不在于代码的实现。其实,我觉得,绝大部分能够想到的应用场景,都可以通过防抖、节流方式实现,比如实时搜索,比如重复订单提交、比如上拉获取最新数据等。事实上,取消请求,请求也是会到达服务端的!只是发出后就不管了,不再接受服务端返回的数据。
场景:当用户连续点击或网络卡顿造成发送多个相同请求时
实现:当发送多个相同请求时,只会响应最后一次请求
原理
基于XMLHtppRequest.abort()
- 根据当前请求的请求方式、请求URL地址、请求参数生成一个唯一的 key
- 再为每个请求创建一个专属的CancelToken(取消token)
- 将 key 与 cancel 函数以键值对的形式存储起来
- 当出现重复请求时,使用 cancel 函数取消前面的请求
- 将取消的请求从集合中移除
具体代码
- 创建CancelRequest.js文件
export default class CancelRequest {
pendings = []
constructor(CancelToken) {
this.CancelToken = CancelToken
}
getCancelToken(config) {
const { CancelToken } = this
return new CancelToken((cancel) => {
const { url, method } = config
const uKey = `{url}&{method}`
this.pendings.push({ uKey, cancel })// config.data为请求参数
})
}
removePending(config) {
const { url, method } = config
const { pendings } = this
const uKey = `{url}&{method}`
const findIndex = pendings.findIndex(p => p.uKey === uKey)
const pendingsLen = pendings.length
if (pendingsLen > 50) {
// 如果pendings存储数量大于50,则释放缓存
pendings.splice(0, pendingsLen - 2)
}
if (findIndex > -1) {
pendings[findIndex].cancel()
pendings.splice(findIndex, 1)
}
}
}
- 在axios中引入
// 主要代码
import CancelRequest from './CancelRequest'
const cancelRequest = new CancelRequest(axios.CancelToken)
// .....
service.interceptors.request.use(
config => {
/* -----------------------重复请求拦截------------------------- */
// requestConfig?.skipCancelRequest 对需要重复请求的情况做处理skipCancelRequest为true跳过(用不到可删除)
if (!requestConfig?.skipCancelRequest) {
cancelRequest.removePending(config)
config.cancelToken = cancelRequest.getCancelToken(config)
}
return config
}
)