背景

在做机构版的时候,一开始为机构设置的人数上限为100,心想就100个,因此前端直接获取全部直接渲染,没有做分页。

这时甲方忽然提出,需要总人数超过400,因为时间比较紧急,我们仅仅只是把请求改了,没有去做对大型数据的优化。

等到测试的时候(400个人数),发现页面的阻塞时间超过1秒,因此有了这篇文章

技术路线

采用的是vue3+ elPlus,

因为使用的是el-table,以及和产品ui沟通,最后选择和病例列表一样使用infinite-scroll的解决方案

因为el-table,自身没有无限滚动的方案,所以选择了第三方集成的库,

el-table-infinite-scroll - npm (npmjs.com)

使用方案

npm install --save el-table-infinite-scroll

局部使用

<template>
  <el-table
            :infinite-scroll-disabled="scrollDisabled"
            v-el-table-infinite-scroll="load"></el-table>
</template>

<script setup>
import { default as vElTableInfiniteScroll } from "el-table-infinite-scroll";

const scrollDisabled = ref(false)
const page = ref(0)
const data = computed(() => orgStore.list)
const load= ()=>{
    page.value++
    new Promise(()=>{}).then((res)=>{
        let data = res.data
        if (page.value * data.pageCount >= data.totalCount) {
            scrollDisabled.value = true
          }
    })
}

</script>

优化过后的性能

79cad1cd6821712609400b56fd1f0cc

上面的为50条数据的渲染曲线,下面的为400条数据的曲线,页面渲染总时间大概为300/1800(8倍),页面阻塞时间大概为430/2400

思考:我们知道,从请求数据到渲染所有页面,包括网络请求js执行(虚拟dom比较,响应式等),真实dom渲染(真实dom树渲染)等等阶段,那么从50条到400条,到底那些地方优化最多?

网络请求

50条数据,平均请求时间大概在50ms,400条数据,平均请求时间大概在100ms,

50条数据大概1.5kb,400条大概6.2kb

image-20240107131448914

image-20240107131439289

根据上图也可以看出,服务器相应时间占大头,大概40ms,但网络的下载时间成倍数增加,直接增加12ms(20多倍,大概是大型数据的数据拼接)

浏览器的执行

其实js执行和dom渲染是交替执行的,但即便如此,当数据量为400的时候其第一次阻塞的执行时间大概为1400ms,其中占500+ms,渲染时间占700+ms,这也就是说js的执行时间大概为500ms,500ms执行完毕后,会进行dom的渲染(nextTick的执行),此时dom的渲染时间大概为700ms,这里的700ms基本可以确定为是真实dom的渲染,然后会进行400ms的渲染,这里的动画渲染应该是浏览器的渲染时间,大概是400ms,400ms执行完毕后,页面就已经完全渲染成功,此时已经能够看到页面,但无法对页面进行任何操作,之后页面继续进行各种事件的绑定,大概是700ms,此时完整的页面渲染完成

image-20240107135949265

上面的页面可能过于冗余,我们简化一下就是

  1. 页面请求,虚拟dom比较 400+ms
  2. 真实dom添加,700+ms
  3. 浏览器渲染,400+ms
  4. 页面事件的绑定,700+ms

而变成50条的数据,上面的行为就变成

  1. 页面请求,虚拟dom比较 100+ms
  2. 真实dom添加,100+ms
  3. 浏览器渲染,70+ms
  4. 页面事件的绑定,100+ms

Q.E.D.