最近在项目中,遇到这种情况,频繁切换tab后,之前tab页面请求回来的数据,会渲染到当前页面,导致页面数据会来回的变化。
1、解决思路一:
使用loading+Promise.all 等接口全部返回数据后,才可以切换下一个tab。
弊端:这样对用户交互特别不友好,尤其是接口响应时间长的话,无法操作其他功能。
2、解决思路二:
使用防抖函数,对于tab页进行点击防抖
弊端:对于响应时间长的请求,还是会导致页面数据变化。
3、解决思路三:
使用全局请求拦截,在切换tab的时候,中断请求:
// axios.js
import axios from 'axios'
// 创建一个全局取消令牌管理器
const CancelTokenManager = {
tokens: [],
cancel() {
this.tokens.forEach(token => token.cancel('页面切换'))
this.tokens = []
},
add(token) {
this.tokens.push(token)
}
}
// 请求拦截器
axios.interceptors.request.use(config => {
const source = axios.CancelToken.source()
config.cancelToken = source.token
CancelTokenManager.add(source)
return config
})
export { CancelTokenManager }
// 在Vue组件中使用
import { CancelTokenManager } from './axios'
methods: {
handleTabChange() {
// 取消所有进行中的请求
CancelTokenManager.cancel()
}
}
存在的弊端:
全局取消风险
- 当切换Tab时,会取消所有进行中的请求,包括其他组件的请求
- 可能会意外中断用户正在进行的其他重要操作
- 不够精细化,缺乏对请求的细粒度控制
性能开销
- 每次请求都需要创建和管理取消令牌
- 随着请求数量增加,令牌管理会带来一定的内存开销
异常处理复杂性
- 全局取消会触发大量的取消异常
- 需要在多个地方添加异常捕获逻辑
- 可能增加代码的复杂度
状态管理问题
- 全局管理器的状态可能会在复杂场景下变得难以追踪
- 可能导致意外的副作用
进行优化:
// 高级请求取消管理器
class AdvancedCancelManager {
private groups: Map<string, Set<CancelToken>> = new Map()
private whiteList: Set<string> = new Set()
// 添加白名单,永不取消的请求
addWhiteList(url: string) {
this.whiteList.add(url)
}
// 注册请求到特定分组
register(group: string, token: CancelToken, url: string) {
// 白名单检查
if (this.whiteList.has(url)) return
if (!this.groups.has(group)) {
this.groups.set(group, new Set())
}
this.groups.get(group)!.add(token)
}
// 智能取消
cancel(group: string, options?: {
exceptUrls?: string[],
timeout?: number
}) {
const groupTokens = this.groups.get(group)
if (!groupTokens) return
// 过滤需要保留的请求
const tokensToCancel = [...groupTokens].filter(
token => !options?.exceptUrls?.includes(token.url)
)
// 批量取消
tokensToCancel.forEach(token => token.cancel())
// 清理已取消的令牌
tokensToCancel.forEach(token => {
groupTokens.delete(token)
})
// 可选:延迟清理
if (options?.timeout) {
setTimeout(() => {
this.groups.delete(group)
}, options.timeout)
}
}
// 自动清理过期分组
autoCleanup() {
const MAX_GROUP_AGE = 30 * 60 * 1000 // 30分钟
this.groups.forEach((tokens, group) => {
if (tokens.size === 0) {
this.groups.delete(group)
}
})
}
}
// axios拦截器集成
const cancelManager = new AdvancedCancelManager()
axios.interceptors.request.use(config => {
const group = config.metadata?.group || 'default'
const source = axios.CancelToken.source()
// 扩展token,携带额外信息
const enhancedToken = {
...source.token,
url: config.url,
timestamp: Date.now()
}
cancelManager.register(group, enhancedToken, config.url)
config.cancelToken = source.token
return config
})
// 使用示例
export default {
methods: {
// 切换Tab时的智能取消
handleTabChange() {
cancelManager.cancel('userPage', {
// 保留某些特定请求
exceptUrls: ['/api/user/keepAlive'],
// 延迟清理
timeout: 5000
})
},
// 添加白名单
preventCancelForCriticalRequest() {
cancelManager.addWhiteList('/api/critical/operation')
}
},
// 定期清理
mounted() {
this.cleanupTimer = setInterval(() => {
cancelManager.autoCleanup()
}, 30 * 60 * 1000)
},
beforeDestroy() {
clearInterval(this.cleanupTimer)
}
}
这个升级版本具有以下高级特性:
智能分组管理
- 按业务模块精确控制请求取消
- 支持动态添加/移除请求组
白名单机制
- 可以豁免某些关键请求
- 防止误删重要的后台交互
增强的取消控制
- 支持部分请求保留
- 可设置取消后的延迟清理
元数据增强
- 每个取消令牌携带额外信息
- 便于后续追踪和管理
自动清理机制
- 定期移除过期的请求组
- 防止内存泄漏
灵活配置
- 可以针对不同场景定制取消策略
这个方案平衡了精确控制、性能和易用性,可以应对更复杂的请求管理场景
如果有更好的方法,可以进行交流呀!!