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)

总结

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

相关推荐
阿蒙Amon2 小时前
TypeScript学习-第7章:泛型(Generic)
javascript·学习·typescript
睡美人的小仙女1272 小时前
Threejs加载环境贴图报错Bad File Format: bad initial token
开发语言·javascript·redis
fanruitian2 小时前
uniapp android开发 测试板本与发行版本
前端·javascript·uni-app
rayufo2 小时前
【工具】列出指定文件夹下所有的目录和文件
开发语言·前端·python
RANCE_atttackkk2 小时前
[Java]实现使用邮箱找回密码的功能
java·开发语言·前端·spring boot·intellij-idea·idea
摘星编程3 小时前
React Native + OpenHarmony:Timeline垂直时间轴
javascript·react native·react.js
2501_944525544 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 支出分析页面
android·开发语言·前端·javascript·flutter
jin1233224 小时前
React Native鸿蒙跨平台完成剧本杀组队详情页面,可以复用桌游、团建、赛事等各类组队详情页开发
javascript·react native·react.js·ecmascript·harmonyos
李白你好4 小时前
Burp Suite插件用于自动检测Web应用程序中的未授权访问漏洞
前端
经年未远5 小时前
vue3中实现耳机和扬声器切换方案
javascript·学习·vue