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)

总结

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

相关推荐
指针向南19 小时前
Chrome读不了HEIC怎么办:原生解码和WASM两条路
前端·图像处理·人工智能·chrome·计算机视觉·wasm
默_笙19 小时前
🚥 给 RAG 装一台心电监护仪:LangSmith 全链路观测(上)
前端·javascript
前端snow20 小时前
ai agent --- mem0 外挂记忆系统
前端
变与不变80621 小时前
js同步和异步难点重点详解
开发语言·javascript·ecmascript
特立独行的猫a21 小时前
用仓颉写一个 Tauri:IPC 的每次往返实现原理(web层到仓颉层的触发过程)
前端·ui·harmonyos·tauri·鸿蒙·仓颉
Dovis(誓平步青云)21 小时前
多个链接不等于多份证据,新闻核验看板怎样合并来源
java·服务器·前端·javascript·人工智能·pdf·电脑
骑着蜗牛撵大象32721 小时前
Qt 事件机制详解:从 QEvent 派生类到事件过滤器的全景指南
前端·python
qq_2518364571 天前
理发管理系统 —— 会员模块
开发语言·前端·python·flask
Dovis(誓平步青云)1 天前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
Frag0ut1 天前
2027 年浏览器展望:Chrome 与 Edge 的 AI 智能体进化方向
前端·人工智能·chrome·edge·浏览器·新功能