页面后端接口比较慢,模块异步卡顿感比较严重,怎么优化处理

31 阅读3分钟

这里只谈前端针对用户感受的优化体验

优化执行层代码逻辑

  1. 检查代码是否有多余的接口调用,导致冗余

问题CASE:

  1. watch监听多次调用导致同样的代码被执行多次
  2. 错误的执行顺序,导致两个函数的执行区域存在重叠

解决方案:

  • 代码层面的时序逻辑更改重构。这个需要结合实际的情况变化,比如频繁切换样式变更DOM行为。
  • 防抖和节流。一个函数有概率短期内执行多次,比如点击button,点击新增文件夹,点击弹窗,输入框输入查询,这种情况都可以使用防抖节流去优化整个体验感受。
  • 监听器+定时器及时解绑,不然全局绑定的监听器/定时器在页面销毁后还在进行浏览器内存和线程消耗
  • 在spa项目中router导航的时候,可以keep-alive,并且设置最多缓存的页面,这样既可以防止组件缓存,防止太多页面缓存在后台占据内存,有些高性能消耗的工作,也可以在后台的时候先关闭,等到用户再切换回前台的时候再去开启,比如轮询排查版本号是否发生打包更新,在页面切到后台的时候就可以把轮询定时器暂停,等到切换回前端页面的时候再去开启
  • shallowRef/shallowReactive减少性能损耗,如果数据无需深层响应式的时候可以使用
  • 利用缓存优化重复的数据,比如前端缓存数据,这个数据特定形况下不会变,如果不变的话则走前端缓存,如果变化则再调后端接口数据
  • 长列表优化:只加载可视区域往外大概一个屏幕的数据,等到下拉的时候再去调后端的接口进行数据的拼接

虽然vue还有自封装的v-once/v-memo等指令工具,但是因为vue本身是细粒度的响应式检测,所以v-memo等指令实际上并没有很频繁使用的场景(也可能我没遇到那种高性能多页面加载的极端case); react里面的useMemo和useCallback,React.memo等则很必要,因为react是以一个模块为单位的

骨架屏&Loading优化白屏加载体验

  • Loading一般组件库都会有自带的组件
  • 骨架屏我用的是vue-content-loader去处理局部组件骨架屏,不过这个是需要自己去绘制骨架屏,优点是自由度高,但是相对比较繁琐;vite-plugin-vue-skeleton据说可以自动生成首页骨架屏,但是公司镜像没有,导致没办法尝试一下
  • errorboundary + suspense + fallback
//主文件,子文件HeavyComponent只要正常执行接口代码就可以
<template>
  <div>
      <ErrorBoundary>
        <Suspense>
          <!-- default 插槽:要等待的异步内容 -->
          <template #default>
            <HeavyComponent />
          </template>
          <!-- fallback 插槽:加载中兜底内容 -->
          <template #fallback>
            <div>加载中...</div>
          </template>
        </Suspense>
    </ErrorBoundary>
  <div>
</template>
<script>
import { defineAsyncComponent } from 'vue';
const HeavyComponent = defineAsyncComponent(() => 
  import('./components/HeavyComponent.vue')
);
</script>

error-boundary的组件vue没有,需要自己实现对应的代码,主要依托于vue的生命周期中的onErrorCaptured函数,具体代码实现Demo如下:

<template>
  <div>
    <div v-if="hasError">
      <div></div>
    </div>
    <slot v-if="!hasError" />
  </div>
</template>

<script setup>
import { ref, onErrorCaptured } from 'vue';

const hasError = ref(false);
onErrorCaptured((err) => {
  console.log(`出现错误了!`);
  hasError.value = true;
  console.error(`err:`, err);
  return true;
});
</script>