Open maicFir opened 2 years ago
你说的假分页,恐怕是不能解决长列表的性能问题哦!你只是分批展示,提升了第一屏的展示速度,但是,卡顿除了你说的这些原因,还有cpu计算太慢的原因,如果你加分页了,那么后面的9次渲染,每一次渲染100条也需要花很多时间,如果你把剩余的9页间隔 加载 比较快,就会造成卡顿,原因是前一页的DIV渲染(应该是异步的)在渲染引擎上都还没有完成,只是js运算完成了,你后面即使JS间隔了100ms也会卡顿。这我是做过实验的、当我在性能好的电脑上看不出问题,反而看到了第一次加载所需时间飞快,而且不影响鼠标操作,我以为速度得到提升了。但是当我在国产机(代表性能差,CPU运算慢)上测试时候,就糟糕了,就出现我上面说的问题了,1000条出现的卡顿和假分页上一样存在。
你说的假分页,恐怕是不能解决长列表的性能问题哦!你只是分批展示,提升了第一屏的展示速度,但是,卡顿除了你说的这些原因,还有cpu计算太慢的原因,如果你加分页了,那么后面的9次渲染,每一次渲染100条也需要花很多时间,如果你把剩余的9页间隔 加载 比较快,就会造成卡顿,原因是前一页的DIV渲染(应该是异步的)在渲染引擎上都还没有完成,只是js运算完成了,你后面即使JS间隔了100ms也会卡顿。这我是做过实验的、当我在性能好的电脑上看不出问题,反而看到了第一次加载所需时间飞快,而且不影响鼠标操作,我以为速度得到提升了。但是当我在国产机(代表性能差,CPU运算慢)上测试时候,就糟糕了,就出现我上面说的问题了,1000条出现的卡顿和假分页上一样存在。
你这种情况就是拿很特殊的情况来测试的,不能拿小步枪去跟高射炮比较,同样的方法在不同机器设备上效果肯定是不一样的,所以要取舍,任何一种方案都有利弊和牺牲,找到最大优且合适自己的项目最终要,比如数据不大,就强行上虚拟列表,为了优化而优化,实际效果还不如没有加虚拟列表的快,所以要因具体情况取舍
我认为这不是一个特殊情况,我们之所以要用解决卡顿,就是只在国产机上(最新的国产机)、性能差的电脑上出现的严重卡顿,性能好的电脑上的卡顿基本是可以接受的。现在政府部门设备国产化了,可不特殊。并不是在 非国产机上的 卡顿才是普遍的,其实也是有性能问题,只是不足以显现。 第一页快,容易让人误以为提升了速度。实际分页是提升了第一页速度,降低了后面页面数据的加载速度。也就是第一阶段集中所有资源来渲染第一页,之后就保持原样的速度,甚至分页的计算和读取数据还增加了微小的时间。 不过你另一篇提到的虚拟列表类似方案是完全可以解决的。
我认为这不是一个特殊情况,我们之所以要用解决卡顿,就是只在国产机上(最新的国产机)、性能差的电脑上出现的严重卡顿,性能好的电脑上的卡顿基本是可以接受的。现在政府部门设备国产化了,可不特殊。并不是在 非国产机上的 卡顿才是普遍的,其实也是有性能问题,只是不足以显现。 第一页快,容易让人误以为提升了速度。实际分页是提升了第一页速度,降低了后面页面数据的加载速度。也就是第一阶段集中所有资源来渲染第一页,之后就保持原样的速度,甚至分页的计算和读取数据还增加了微小的时间。 不过你另一篇提到的虚拟列表类似方案是完全可以解决的。
是的,分页方案是减少首屏渲染的时间,但是提升整个页面的速度会受到分页dom内容以及其他多方面影响,比如第一页只展示10条数据,但是这10条数据又有树结构的数据,所以此时分页也并不能感受到这样做会让页面很快,此时应该是分页+加上分页里面数据的按需显示,就会很快,从而提升了第一页速度,只是在视觉上让人感受快些,按照文中时间切片去加载数据或者分页加载,实际是有点掩耳盗铃的做法,因为看不见的时候,偷偷给你加载好了,只是我们页面上没看见而已。总体而言会比首次一次性的大数据渲染要好点,在虚拟列表里,也是根据可视区域去计算数据按需加载数据,在性能差的电脑,找到一个最有效的方案即可,虚拟列表也不是万能,只是在大数据渲染时候提升dom渲染,改善了卡顿用户体验,如果不是大数据,肯定是直接拿数据渲染来得快的
你说的掩耳盗铃的加载后面数据其实都不存在,window上是因为性能够用,本身不分批都感受不到卡。如果在window上不分批的大数据量是很卡的情况,分批展示也会在时候卡,这种卡是发生鼠标交互操作上的卡,而不是视觉上的加载延迟。总结就是,第一屏渲染界面飞快,但立即操作就是卡的。
最近遇到一个 bug,测试同学用脚本添加近 1000 条数据就把页面搞崩了
真是惨重,而且
chrome
页面请求的接口无任何响应,后端数据有分页,前端也有分页,但是由于数据量过大,ivew
的table
太不经打了,因为是一个table
的tree
,于是这个锅,前端背了如果你有跟笔者一样使用
ivew
的table
经历,希望这篇文章能给你实际项目中带来一点思考和帮助。正文开始...
写一个栗子看看 ivew
table
承载的数据边界是多少笔者写了一个简单的栗子来,测试页面卡顿的情况,新建一个
index.html
,贴上关键代码 ::: details code:::
新建一个
index.js
,引入页面中 ::: details code::: 我本地新建一个模拟接口数据的操作,这里笔者用了一个
mockjs
造数据,使用axios
这个库做ajax
请求具体看下
index.js
这个主页面的js
::: details code:::
以上代码片段有些长,但是核心思想非常简单,我模拟了一个页面列表需要的数据以及入参请求的分页参数,列表会根据我设置的分页参数,请求拿到数据,渲染到页面中。
接下来看下
mockserver.js
这个是一个模拟接口的一个工具库,可以看下片段 ::: details code:::
mock
数据已经准备 ok,我们看下页面就是这样的打开控制台
netWork
的perfomance monitor
可以看到js heap size
右侧非常平稳(这里可以看到页面内存溢出情况,如果是平稳的,说明内存溢出的可能性很小),在10
条数据时候,页面也非常流畅当我把总条数调至
100
时cpu
在我修改总条数,然后点击刷新按钮操作,cpu
和内存
都有往上飙升了,但是内存溢出依然不是很明显,点击页面也并无卡顿。当我把页面总数调至
500
时,此时页面内存溢出和 cpu 又是怎么样当我点击页面刷新按钮操,然后点击列表的树操作时,页面已经有明显的卡顿了,但页面没有卡死,当我直接把总条数修改
1000
时,整个页面已经卡死。500
条数据就已经感受到页面卡顿了,当为1000
条时,页面直接卡死,因此在测试同学极限测试的情况下,生产环境页面直接崩了,这时候,你不可能跟测试说,你为啥要造那么数据?在极端情况下,也许就是有测试的这种情况,看了官方文档,临时做了一个补救方案,就是点击那个
tree
的时候,再异步加载children
数据,但是...,第二天测试告诉我,页面又崩了,于是,这种方式是不行了,那么加个页面吧,把树的子集页面用一个弹框页面展示,这样首页只加载第一级数据,二级数据让后端做了个分页查询,再给前端渲染。终于这样页面不卡顿了,测试添加
1000
条数据,页面不卡顿了,但是为啥ivew
的 table 渲染数据,会造成页面内存溢出如此严重,去官方github
上看了一下 table 组件的源码在
ivew
的table
组件,是用render
,根据columns
生成colgroup
,根据data
生成tr
、td
,具体可以看下table-body::: details code
:::
在循环
data
中创建tr
,而且还有递归寻找getChildNode
操作,tr
上还绑定了许多事件,当我们点击tree
时,会触发tr
的 mouseenter,click 等事件,如此多的事件绑定在tr
上,在数据量很大的时候,绑定的事件越多,造成内存泄漏越是严重,而且是每个tr
上都是直接绑定nativeOn
等这些事件。所以ivew
的 table 造成内存的泄漏直接让页面卡死。ivew
的 table 既然这么不经打,那么我测试下elementUI
的table
是否比ivew
更好。笔者糊了一个一模一样的测试页面 ::: details code
:::
打开浏览器,直接设置
1000
,elementUI
的table
真的吊打ivew
几条街 cpu 几乎没有变化多少,内存泄漏也是几乎没有,在一段时间内,几乎是保持不变的。用
5000
调试,页面有稍微卡顿了,10000
条数据测试,终于把页面搞崩了。点击tree
页面明显卡顿,但即使是这样也比ivew
1000 条的测试数据页面要好得多。由此可见笔者已经把
ivew
table 最大的问题踩了一个坑。 关于elementUI
的 table 可以去官方库看下,比ivew
处理要优雅得多,具体参考ele-body看到这里,如果
table
大数据渲染,有没有比较好的实践方案。因为 1w 条数据的情况,即使是elementUI
怎么扛打,也显得力不从心。虚拟长列表方案优化
虚拟列表优化,这是大数据量优化的一种手段,大数据渲染 dom 导致页面卡顿,我们尝试用虚拟长列表方案去实践下
为快速实现业务
table
性能,我们采用第三方虚拟列表umy-ui
,专门解决 table 卡顿问题新建一个
index-vitual.html
::: details code::: ::: details code
::: 就是引入
umy-ui
的两个组件即可,主要注意u-table
的几个props
1、
use-virtual
主要是打开虚拟列表2、
height
设置一个固定的高度,或者设置一个max-height
,如果不需要设置高度,内容需根据内容滚动,则关闭虚拟列表use-virtual
这个参数不设置即可3、
treeConfig
这个参数设置是否有tree
,当设置树时u-table
上必须设置row-id="id"
,否则树不会出来,并且cloumns
上设置hasChildren
标识4、
u-table-column
设置:tree-node
属性,指定列中哪个props
展开更多 API 可以参考官网
当我们将参数调节至首页 1000 条时,其实
table
的 tr 始终中 16 条左右用该方案极大的减少了列表
dom
的渲染,避免了一次性渲染 1000 个tr,td
。因此极大的提升了table
的渲染,页面的性能也会提升不少。最后,如果你将总条数调至 10000,你最后还是会发现页面
cpu
直接上升至100%
,页面明显的卡顿了几秒钟,这也表明,此时无论页面是否虚拟列表方案,造成页面卡顿与js
声明额数据量也有一定关系,当定义的数据过大,在内存没有释放的这段过程中,如果造成页面内存溢出或者堆栈过大,那么也会造成页面的卡死。总结
1、
ivew
的table
性能很差,比较elementUI
,1000
数据ivew
就能让你浏览器崩掉,所以慎用ivew
table 的大数据量,有坑2、
elementUI
的 table 组件很优秀,1000
条能扛得住,但上了5000
后,就明显扛不住了,所以采用umy-ui
虚拟列表渲染3、
umy-ui
方案可以极大的优化大数据table
渲染,但是数据量超过 1w+,甚至更多,那么虚拟列表也是没得救了,页面依然会卡顿。因此造成页面卡顿的因素很多,我们减少事件操作、闭包、全局变量等等这些尽量减少内存的消耗,以及页面的
GUI
渲染,这样就可以极大提高页面的访问性能。关于
虚拟长列表方案
,后续我会写一篇深究虚拟长列表的技术文章,除了这种方案优化 table,笔者想到,另外两种方案一种是假分页,如果后端一次性返回了
1000
条数据,那么我在前端按照上拉滚动的方式,每次加载100条
的方式去渲染,这样分10页
就可以加载完毕了,比起一次性加载1w+
应该会有明显的提升,后续会写个测试 demo 验证一下。二种是增加二级页面,将大数据做本地
indexDB
存储,然后从indexDB
中做前端分页查询。4、本文示例code example