Vue公共loading升级版(处理并发异步差时响应)

  • Vue公共loading升级版(处理并发异步差时响应)已关闭评论
  • 16 次浏览
  • A+
所属分类:Web前端
摘要

公共loading是项目系统中很常见的场景,处理方式也不外乎三个步骤:
1.通过全局状态管理定义状态值(vuex、pinia等)。
2.在程序主入口监听状态值变化,从而展示/隐藏laoding动画。
3.在请求和相应拦截器中变更状态值。

公共loading是项目系统中很常见的场景,处理方式也不外乎三个步骤:
1.通过全局状态管理定义状态值(vuex、pinia等)。
2.在程序主入口监听状态值变化,从而展示/隐藏laoding动画。
3.在请求和相应拦截器中变更状态值。

第一二步骤处理大同小异,但在第三步中,网上很多博文分享的方法是:在请求拦截中展示loading,在响应拦截器中判断收到成功响应时直接隐藏loading,这种方法看似可行但实际过程中却有问题。
例如,假设在第0秒时同时向后台发送了两个异步请求A和B,由于网络或处理逻辑不同,A请求0.5秒秒收到成功响应,B请求2秒才收到。那在第0.5秒,响应拦截器就会把loading状态变更,结束loading动画,但此时B请求还没收到返回。如果用户接下来的操作同时需要A和B请求的数据,提前结束动画会让用户体检变差。

解决思路:
定义一个全局对象来存储每个接口的响应状态,直到每个请求接口都收到响应才变更状态,结束loading动画。因为键名的唯一性,可以使用接口路径(或唯一接口编号)作为键名。请求时添加一个键值对,响应时变更键值,同时遍历对象状态值进行判断

let apiStatusList ={   '/api/a':true,//true请求中   '/api/b':false //false请求完成 } 

具体操作如下(以vue3的pinia为例):
定义一个loading.js

import { defineStore } from 'pinia'; export const useLoadStore = defineStore('storeLoading', {   state: () => {     return {       apiStatusList:{},       loading:false, //网络加载状态,true加载中     };   },   actions: {     updateLoadingState(value){       this.loading = value     },     setApiStatusList(value){       this.apiList = value;     }   } }); 

拦截器处理:

import axios from 'axios'; import { useLoadStore } from '../stores/loading';  const request = axios.create(); //请求拦截 request.interceptors.request.use(   (config) => {     //公共loading     const loadStore = useLoadStore();     let statusList = { ...loadStore.apiStatusList };     statusList[config.url] = true; //接口赋值为请求中     loadStore.setApiStatusList(statusList);     if (!loadStore.loading) {  //判断loading是否正在展示中       loadStore.updateLoadingState(true);     }      return config;   },   (error) => {     return Promise.reject(error);   } )  //响应拦截 request.interceptors.response.use(   (response) => {     const loadStore = useLoadStore();     let statusList = { ...loadStore.apiStatusList };     statusList[response.config.url] = false;  ////接口赋值为请求完成     if (!Object.values(statusList).includes(true)) { //遍历对象,判断接口是否全部返回       if (loadStore.loading) {         loadStore.updateLoadingState(false);         loadStore.setApiStatusList({});       }     } else {       loadStore.setApiStatusList(statusList);     }   },   (error) => {//有接口报错,重置loading     const loadStore = useLoadStore();     if (loadStore.loading) {       loadStore.updateLoadingState(false);       loadStore.setApiStatusList({});     }   } ) 

App.vue监听状态变化

//监听store状态值时需要传入function watch(()=>loadStore.loading,(newValue, oldValue)=>{   if(newValue){     showLoadingToast({       duration: 0,       forbidClick: true,     });   }else{     closeToast();   } })