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)

总结

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

相关推荐
Mercury-circle1 分钟前
JavaScript基础知识合集笔记1——数据类型
开发语言·javascript·笔记
一天睡25小时12 分钟前
前端性能优化面试回答技巧(一)
前端·面试
樊小肆12 分钟前
Vue3 在线 PDF 编辑 2.0 缩放拖拽、渲染优化功能解析
前端·vue.js·开源
程序员韩立13 分钟前
精通 React Hooks:从核心技巧到自定义实践
前端
WEI_Gaot14 分钟前
React Hooks useRef useId
前端·react.js
一天睡25小时15 分钟前
视频HLS分片与关键帧优化深度解析
前端·javascript
孤鸿玉16 分钟前
[Flutter小试牛刀] 低配版signals,添加多层监听链
android·前端·响应式设计
漫漫漫丶16 分钟前
基于Node+HeadlessBrowser的浏览器自动化方案
前端
WEI_Gaot16 分钟前
React Hooks useContext useReducer
前端·react.js
用户20311966009619 分钟前
空合并运算符
前端·后端