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)

总结

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

相关推荐
GIS程序媛—椰子15 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00121 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端24 分钟前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x27 分钟前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
木舟100928 分钟前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤439138 分钟前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢1 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安1 小时前
前端第二次作业
前端·css·css3
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习