项目中的优化-tab页频繁切换,页面数据混乱

最近在项目中,遇到这种情况,频繁切换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)
  }
}

这个升级版本具有以下高级特性:

智能分组管理

  • 按业务模块精确控制请求取消
  • 支持动态添加/移除请求组

白名单机制

  • 可以豁免某些关键请求
  • 防止误删重要的后台交互

增强的取消控制

  • 支持部分请求保留
  • 可设置取消后的延迟清理

元数据增强

  • 每个取消令牌携带额外信息
  • 便于后续追踪和管理

自动清理机制

  • 定期移除过期的请求组
  • 防止内存泄漏

灵活配置

  • 可以针对不同场景定制取消策略

这个方案平衡了精确控制、性能和易用性,可以应对更复杂的请求管理场景

如果有更好的方法,可以进行交流呀!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值