实现当上一个请求未完成时进行重复请求则取消上一个请求,以及当路由跳转时取消前一个路由中未完成的请求
实现思路
将每一个请求的取消函数保存起来,当请求正常结束时,将保存的取消函数清除,当重复进行相同请求时,调用上一个请求的取消函数,并用新请求的取消函数进行覆盖,监听路由变化,当路由跳转时,调用其它路由中请求的取消函数
实现方法
- 使用一个map来保存,key和value分别是每个请求的标识和请求对应的取消函数
export const CacheUtil: {
cache: { [key: string]: any },
clearCache: (key: string) => void,
clearOther: (key: string) => void,
} = {
// 映射关系
cache: {},
// 根据提供的键名取消对应的请求
clearCache(key: string) {
if (key) {
const cancle = this.cache[key]
if (cancle && typeof cancle === 'function') {
cancle()
delete this.cache[key]
}
}
},
// 根据提供的页面路径取消其它路径的请求
clearOther(herf: string) {
if (herf) {
Object.entries(this.cache).forEach(([key, cancle]) => {
if (key.split("__")[1] !== herf) {
cancle()
delete this.cache[key]
}
})
}
}
}
- 存入缓存和删除缓存的时机分别是请求开始之前和请求结束之后,对应axios的拦截器。这里使用axios的cancleToken来拿到每个请求的取消函数:
// 在请求拦截器中
this.instance.interceptors.request.use(
(config) => {
// 拼接method、请求url以及路径名来保证一个cacheKey表示一个请求
let cacheKey = config.method + '_' + config.url + '__' + history.location.pathname
if (cacheKey) {
// 将上一个未完成的相同的请求中断
CacheUtil.cache[cacheKey] && CacheUtil.clearCache(cacheKey)
// 将当前请求对应的取消函数存入缓存中
config.cancelToken = new axios.CancelToken((c) => {
if (cacheKey) CacheUtil.cache[cacheKey] = c
})
// 将cacheKey保存在config中,以便在相应拦截器中通过cacheKey将缓存释放
config.cacheKey = cacheKey
}
return config
},
(error: any) => {
return Promise.reject(error)
}
)
// 在响应拦截器中
this.instance.interceptors.response.use(
(response) => {
// 请求正常完成,将缓存释放,下面请求错误时也一样
const cacheKey = response.config.cacheKey
cacheKey && delete CacheUtil.cache[cacheKey]
return response
},
(error: any) => {
if (error.config) {
const cacheKey = error.config.cacheKey
cacheKey && delete CacheUtil.cache[cacheKey]
}
return Promise.reject(error)
}
)
- 使用umi3.x的history.listen进行路由监听,当路由变化时调用CacheUtil.clearOther
import React, { useEffect } from 'react'
import { history } from 'umi'
import { CacheUtil } from '@/utils/CacheUtil'
const Page = () => {
useEffect(() => {
const unlisten = history.listen((location, action) => {
CacheUtil.clearOther(location.pathname)
})
return () => {
unlisten()
}
}, [history])
return (<div>Page</div>)
}
export default Page