下栽の地止:https://www.itwangzi.cn/4372.html

前几日子公司有两个较为关键的组件从 vue2 升级换代到 vue3,升级换代后辨认出 element-plus table 的操控性较之 vue2 版上升十分轻微。
自订列全数键入的情景下(20 行 x 180 列),条目中的控制器转换,费时从原本的 400-500 微秒上升到 7-8 秒,严重影响使用者新体验,历经较长的操控性试验、debug,找出了两处较为核心理念的强化点。
先上看呵呵 20 行 x 180 列情景下各强化点的操控性原始统计数据,为须建随机性,每一情景单厢测 3 次。

大体强化文本如下
预备组织工作
首先初始化两个 vue3 项目,引入 element-plus,并使用 el-table 实现两个 20 行 * 180 条目格。
最小化销售业务 demo 创建
核心理念 table 代码代码如下表所示,完整代码参见:table-base | table-performance-demo[1]
渲染费时计算逻辑
渲染费时计算逻辑如下表所示,利用 script 阻塞,来计算渲染费时
/*
当前显示:{{ `${rowCount}行${customColCount + 2}列` }}, 显示/隐藏 table:
/ 1000}s`);
}, 0);
}, 200);
};
操控性统计数据,与 performance 费时对比
table 渲染、switch 转换试验费时如下表所示
table 隐藏到显示 gif 图
table-base-6-8-s.gif
switch 从关到开 gif 图
table-base-switch-3-8-s.gif
为了验证我们自己写的费时原始统计数据的准确性,这里在 switch 控制器时,打开了 performance 录制,具体如下表所示图
页面显示渲染费时:4.524s,performance 中两个 Long Task:2.29s + 2.17,加上非 Long Task 部分,统计数据基本一致,因此我们自己写的费时计算逻辑是基本准确的
table-base-switch-performance.gif
另外,开启 performance 录制时,比不录制时要稍微慢点。下面来开始强化吧!
ref 改 shallowRef
理论依据与可行性分析
条目中的控制器转换时,table 虽然只是两个节点发生了变化,但依旧触发了完整的 vue patch 比对更新逻辑,费时较久。
上看两个官方的解释:渲染机制 | Vue.js
(https://cn.vuejs.org/guide/extras/rendering-mechanism.html#compiler-informed-virtual-dom”)
理论上,减少积极响应式统计数据依赖,就可以提升操控性。
shallowRef() 是 ref() 的浅层作用形式。仅当 xx.value 发生变更时,才触发积极响应更新,减少深层次的积极响应依赖,可以提升 patch 比对操控性。
参考:指南 – 减少大型不可变结构的积极响应性开销
(https://cn.vuejs.org/guide/best-practices/performance.html#reduce-reactivity-overhead-for-large-immutable-structures )
这里主要修正两种统计数据从 ref 到 shallowRef
这里有个问题,把 data、columns 改成 shallowRef 对功能会不会有影响?
基于以上三点,在我们销售业务中,这个修正是可行的。提醒:如果想在你自己的项目中使用该强化,需要先做好试验。
下面上看具体修正细节
拷贝 element-plus table 源代码到当前项目
当前最新的版是 2.2.8,打开 element-plus/releases ( https://github.com/element-plus/element-plus/releases),下载最新版代码,将 table 目录(element-plus-2.2.28/packages/components/table) copy 到项目中的 src/table 下,删除目中无用的__test__ 试验目录
新开两个路由,/new 指定到两个新增的 table 组件内,较之原本 table 组件,只增加一行代码,当前组件内使用我们自订修正的 table。
完整代码参见:2-table-use-source | table-performance-demo
(https://github.com/zuoxiaobai/table-performance-demo/tree/2-table-use-source)
引入后报错 [plugin:vite:import-analysis] Failed to resolve import “@element-plus/directives” from “src\table\src\table.vue”. Does the file exist?
做一些修正,让代码可以在我们自己的项目中跑起来,方便修正、调试源代码
在 table 目录中搜索 \@element-plus 相关关键字,并进行批量替换
搜索 `@element-plus/components` 改成直接从 element-plus 引入
修正源代码 – ref 改 shallowRef
在 src/table/src/store/watcher.ts 中,将 data 和 columns 统计数据从 ref 改成 shallowRef,具体代码参:table-ref-shallowRef | table-performance-demo
(“https://github.com/zuoxiaobai/table-performance-demo/tree/table-ref-shallowRef”)
另外在 中 表格前面增加下面一行,标记调用的是我们修正的 table 组件
操控性统计数据(费时减少17-20%)
table 渲染、switch 转换试验费时如下表所示
table 隐藏到显示 gif 图
table-ref-shallowRef.gif
switch 从关到开 gif 图
table-ref-shallowRef-switch.gif
getColspanRealWidth 强化
当页面卡顿时,可以通过 performance 试验性能。下图是点击 switch 控制器后的操控性统计数据。可以看到
我们来查看这个表达式费时的原因,主要是在 tr 渲染时调用该表达式,计算每列的宽度
具体实现如下表所示,只用到了 realWidth, width 特性,且 columns.value 是积极响应式依赖,可以修正为非积极响应式统计数据,看是否能减少费时。
这里我们新建 optimizeColumns 变量,存储表达式中使用的 realWidth 和 width,将这个非积极响应式统计数据传入到 getColspanRealWidth 函数内部使用,
完整代码参见 getColspanRealWidth-optimize | table-performance-demo
( “https://github.com/zuoxiaobai/table-performance-demo/tree/getColspanRealWidth-optimize”)
// src\table\src\table-body\render-helper.ts
const optimizeColumns = columns.value.map((item) => {
return { realWidth: item.realWidth, width: item.width };
});
columns.value.map((column, cellIndex) => {
// …
columnData.realWidth = getColspanRealWidth(
optimizeColumns, // 传入表达式内部时,使用非积极响应式统计数据
colspan,
cellIndex
);
// …
})
费时从 200ms 上升到 0.7ms
修正好后再次试验操控性,惊喜的辨认出,这个表达式的费时从 200ms+ 上升到 1ms 内,render 操控性明显提升。1.54s + 1.45s = 2.99s
操控性统计数据(费时减少7-20%)
table 渲染、switch 转换试验费时如下表所示
table 隐藏到显示 gif 图
get-width-optimize-table.gif
switch 从关到开 gif 图
get-width-optimize-switch.gif
销售业务强化 tooltip disabled 改 if
历经上面的强化后,我们意识到,即使是很细微的积极响应式统计数据强化,也会对操控性带来较大影响。那销售业务逻辑中是否也存在这样的统计数据呢?
于是采用注释 + 将 el-table-column 插槽换成静态节点 <span>123</span>的方法,试验具体是哪里费时较长,然后针对性强化。
历经试验,辨认出将自订列中的 el-tooltip 换成静态节点后,操控性有极大提升。
placement=”top-start”
:disabled=”!(item.prop === column1 && scope.row[item.prop])”
>
{{ “tooltip显示” + scope.row[item.prop] }}
{{ scope.row[item.prop] }}
</el-tooltip> –> <span>123</span></template></el-table-column>如下表所示图,switch 控制器转换费时从 2.7s 左右减少到 0.5s 左右。performance 面板可以看到 patch 基本没有了,应该是模板编译时静态节点标记后,更新时就不用比对了。
基于这个思路,el-tooltip 组件会成倍的增加 patch 比对费时,减少这个节点数量即可增强操控性。
为了少些一些代码,el-tooltip 使用 disabled 特性,用于在特定情景下隐藏 tooltip,这一部分统计数据可以不使用 el-tooltip 节点,改动如下表所示,使用 v-if 替换 disabled 特性功能,这样虽然会有重复代码,但可以减少节点数。
placement=”top-start”
:disabled=”!(item.prop === column1 && scope.row[item.prop])”
>
{{ “tooltip显示” + scope.row[item.prop] }}
{{ scope.row[item.prop] }}
–> <spanv-if=“!(item.prop === column1 && scope.row[item.prop])”> {{ scope.row[item.prop] }}</span><el-tooltipv-elseplacement=“top-start”><template #content><span>{{ “tooltip显示” + scope.row[item.prop] }}</span></template><span>{{ scope.row[item.prop] }}</span></el-tooltip></template>再次试验操控性,可以看到操控性并没有上升多少,switch 控制器转换可以做到 0.5s 左右刷新
操控性统计数据(费时减少80%)
table 渲染、switch 转换试验费时如下表所示
table 隐藏到显示 gif 图
tooltip-optimize-table.gif
switch 从关到开 gif 图
tooltip-optimize-switch.gif
总结
如下表所示图,通过 3 个小的细节改动,将 table 渲染费时从 6.88s 减少到 1s 左右,平均减少 85% 渲染费时,使用者新体验基本达到预期。
完整 demo github 地址:
https://github.com/zuoxiaobai/table-performance-demo
在 vue3 项目中,积极响应式统计数据这块要特别注意。当遇到较为慢的情景时,建议采用如下表所示方法进行操控性强化