确定在GridManager内实现万条不卡的想法,最早呈现于2021年初同郑某人
和杨某人
的饭局上。现在性能曾经实现,整顿下这个值得记录的过程。
现状剖析
在虚构滚动落地前,针对于现有逻辑的革新是个前置条件。
上方gif
内演示了在实现万条不卡前,表格组件所领有的局部能力。因为这些能力搭建于原生跨框架的构造上,所以在须要对渲染逻辑进行较大范畴革新时,原先的能力就成为了不小的包袱。
因而在不影响现有性能的状况下反对万条不卡,须要按序实现以下三个步骤:
- tbody区域的数据驱动革新:
升高性能复杂度
- 差异化更新:
缩小DOM节点的更新频率
- 虚构滚动:
缩小DOM节点的更新数量
三个步骤
基于数据驱动,构建差异化更新,最终实现虚构滚动。
1、数据驱动
随着js框架的呈现,数据驱动扭转了前端组件的渲染逻辑。
对于一个脱离框架的原生表格组件,尽管须要自行实现数据驱动,但难度其实不大,只需将tbody区域内的所有渲染逻辑进行整合,并向外透出惟一的数据变更接管函数。
这个函数起到一个承前启后的作用,隔离了数据层与视图层。在数据变更时被触发,并依据触发的不同场景对tbody区域进行渲染。
假如这个函数叫changeTableData
,实现数据驱动后的逻辑如下:
// 当数据变更时,函数会被触发,由该函数来判断哪些DOM应该被更新。changeTableData() { const data = getTableData(); // tbody render renderTbody(data);}// 场景一: 分页被执行时changeTableData();// 场景二: 某条数据被批改时changeTableData();
数据驱动只是一个先决条件,差异化更新和虚构滚动才是解决卡顿的伎俩。
2、差异化更新
表格组件所依赖的数据无论是什么格局,都会存在一个与渲染后果相匹配的数组。
[{ id: 1, name: '张三'},{ id: 2, name: '李四'},{ id: 3, name: '王五'}]
这个数组在特定状况下,返回后果会存在与已渲染数据雷同或局部雷同的状况。比如说: 在触发搜寻后再次返回了以下数据:
[{ id: 1, name: '张三丰'},{ id: 2, name: '李四'},{ id: 3, name: '王五'},{ id: 4, name: '赵六'}]
将两次的返回后果进行比拟,能够发现:
- 数组的长度减少1
- 索引为0的name产生了变动
如果不加甄别的进行从新渲染,就会存在不必要的DOM操作,特地是在数据量较大时,对性能的耗费是极大的。
为避免不必要的性能耗费,须要基于数据驱动的逻辑对DOM进行差异化更新。
const diffTableData = (oldData, newData) => { // 通过比对oldData与newData,生成一个新的数组 const diffList = []; // ...省略掉的比对逻辑 return diffList;};
通过diffTableData
函数,比对数据失去以下后果:
[{ id: 1, name: '张三丰'},,,{ id: 4, name: '赵六'}]
在失去排重的后果后,并数据进行渲染。
changeTableData() { const oldData = getOldData(); const newData = getNewData(); // 提供diff函数,将比对后的数据进行渲染,未变更的DOM不更新 const diffData = diffTableData(oldData, newData); // tbody render renderTbody(diffData);}
以上示例仅是用于展现逻辑,残缺实现可点击github地址查看diffTableData
函数。
3、虚构滚动
用户看到的一万条数据,其实在前端只渲染了20条。
当原生表格的tbody区域实现数据驱动后,通过在changeTableData
中提供勾子供scroll
事件调用即可实现虚构滚动。
在勾子内通过滚轴的scrollTop
计算以后须要显示的数据,通过margin
填充虚构局部的滚轴高度。并在这些根底上减少一些防抖机制,让虚构滚动更晦涩。
changeTableData() { // 在tbody区域滚轴事件中调用 virtualScrollMap[key] = () => { // 1、计算以后须要显示的数据,保障tr的最大值不超过20 // 2、通过margin填充虚构局部的滚轴高度 // 3、减少防抖 };}// tbody区域的滚轴事件onScroll = () => { // 调用changeTableData提供的勾子 virtualScrollMap[key]();}
以上示例仅是用于展现逻辑,残缺实现可点击github地址查点changeTableData
函数。
成果展现
tbody区域实现数据驱动
、差异化更新
、虚构滚动
后,在2021年的最初一天,万条不卡最终以即定步骤得以公布,成果如下:
new GridManager(table, { // 启用虚构滚动 @2.18.0 virtualScroll: { // 在应用supportTreeData与fullColumn时虚构滚动有效。 // 应用动态导出,必须配置handler,否则导出数据长度为virtualNum; // 打印时仅对以后配置virtualNum的条数失效 useVirtualScroll: true, // 理论渲染的Tr数,该数值大于当前页数据长度时,虚构滚动不失效 virtualNum: 10 }, // ...其它配置项});
从gif
中能够看出,尽管存在10000条数据,但tbody区域的tr节点始终放弃在10个。table上的margin依据滚动轴的地位一直变动,撑持着表格区域的高度。
开源不易
最近听杨某人
说要搞个组件库,闲聊间想起六年前GridManager的样子,真是一言难尽、一路艰苦。
开源不易,心愿能够坚持下去。