Vue3 简单实现解决前端常见的竞态问题

最近遇到一个业务场景,tabs切换三个标签页。每切换一个tabs,就会请求一次数据,然后把数据放到已经清空的一个数组内。那么因为有的数据多,有的少。就会造成第二个tabs的数据展示到第三个tsbs内。虽然这些数据会在切换时候拨乱反正。但这是个大问题。

前端demo

当快速切换tab时如果这时用户终端设备网络不好,或者两个tab请求返回数据的时差先后问题,就会导致类似标签2展示的是标签三的数据

解决方法

这里我就认为大家都知道什么是数据竞态了,如果还有什么不懂得地方就看看大厂们怎么说的

# 字节:如何解决前端常见的竞态问题

# 飞书:前端提到的竞态问题,在 Android 上怎么解决?

1...添加Loaing(禁用页面)

这是最简单的方法,但坏处就是如果时间过久,对用户体验的感觉不好,但是阻断了一切问题的发生

2...忽略不匹配的返回数据

比如:我们在一个tabs标签页切换的时候都会有一个activeIndex变量,我们只需要在请求返回数据的赋值时候进行判断是否是此tab页签的数据在进行赋值即可,这样子也可以解决
我这里是有将activeIndex进行传参给后端的,所以在拿到res后可以用局部作用域的params和全局的activeIndex进行判断

js 复制代码
// 获取表格数据
    async getTableDatas() {
      try {
        //......忽略前面的操作
        let res = await getRefundList(params)
        // 💥💥💥防止切换太快导致的数据不一致
        if (params.conditionsMap.reviewStatus === this.activeIndex) this.tableData = res.data.data.data;
      } 
    },

3...Axios 取消请求

我这里只写了关于Axios (v0.22.0)以后版本的取消请求方法,因为再次之前的取消请求是通过CancelToken Api的方法,但是在0.22.0版本就开始被弃用了
v0.22.0 开始,axios 支持以 fetch API 方式的 AbortController 取消请求

js 复制代码
// 这是官方写法
const controller = new AbortController();  
  
axios.get('/foo/bar', {  
signal: controller.signal  
}).then(function(response) {  
//...  
});  
// 取消请求  
controller.abort()

当然写的太关于简单了,意思就是先使用new AbortController() 创建一个实例,将这个实例传给axios方法的最后一个参数signal,就可以将该请求与该实例绑定起来,后面需要取消的话只需调用实例的abort()方法即可取消请求,我不太喜欢写在拦截器中,感觉不好单独控制(当然这是我个人的代码风格,如果以后需要优化的话在弄吧 touch 🐟)

js 复制代码
// .vue文件
// 取消请求
let controller = ref(null)
const handleClick = async () => {
  try {
    //在下一次请求前判断实例是否有请求
    if (controller.value) controller.value.abort()
    controller.value = new AbortController()
    let res = await cancelAxios(
      { id: activeTab.value },
      { signal: controller.value.signal }
    )
    data.value = res.data
    controller.value = null // 清空实例对象
  } catch (error) {
    console.log(error)
  }
}
js 复制代码
// .request文件
import request from '../index'
// post就将signal参数传给最后一个参数即可 ,如果是get传给第二个参数即可
export const cancelAxios = (data, signal) => request.post('/cancel', data, signal)
  
export const getCancelAxios = (signal) => request.get('/getCancel', signal)

总结

根据实际情况选最适合自己的方法即可,各有各的好,哪个方便就用哪个就好了(如果还有其他更好的方法,可以再评论区讨论讨论)

相关推荐
崔庆才丨静觅10 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606111 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅11 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅11 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅12 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment12 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅12 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊12 小时前
jwt介绍
前端
爱敲代码的小鱼12 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax