长列表优化
, 是页面性能优化
中的一个比较常见的问题,也是面试中的常客。面试
恰好最近在的项目中, 遇到了一个长列表的性能问题,试过多种方案, 最后得以解决。chrome
今天就给你们分享一下。浏览器
用户须要批量修改 Product中 sku 的 映射关系,能够选择的 Product 的 数量不限
。性能优化
每一条sku 对应以下结构:antd
由于能够选择的sku数量是不限的, 又不能分页, 只能作到一个列表里。dom
因而, 长列表出现了。工具
刚开始的方案是作一个虚拟列表
。性能
具体就是经过监听sroll事件,每次滚动后计算通常元素位置(top和height)测试
而后,经过渲染三屏的方式,把一段数据渲染到页面上。优化
数据量很少的时候, 没什么问题。
当选择几百上千条sku 的时候, 快速滑动, 就开始出现卡顿。
如图所示:
做为对比,看一下优化后的效果:
在chrome调试工具下,边拖动列表边观察dom的变化。
发现,dom的卸载/挂载/更新的状况都出奇地慢,鼠标已经停下来,能明显感受到过一会dom才装载完成,因此极可能是dom的渲染性能问题。
定位到渲染性能有问题的dom身上,即每个 Item(renderFakeTable)。
使用普通文本代替Item,在一样多数量的列表状况下,简单的dom明显会顺畅不少,可是,仍然会出现空白问题。
继续观察renderFakeTable中的每个元素(能够借用devTools Profiler)。
最简单粗暴的方式就是去除某一类的组件,而后经过不断自测的方式,找出最有可能影响渲染效率的元素:
SearchSelect(基于antd的Select封装的一个业务组件)。
因此,影响渲染性能的元素极可能就是它。
除了组件的问题,还有多是渲染
的问题。
首先,原来无限滚动的逻辑就是基于scroll事件,经过不断滚动触发的回调,从新计算渲染到页面上的区间。
其次,为了动态调整可视区域的元素,使用了MutationObserver。
致使空白问题则会有这几种可能:
不幸运的是,以上的可能都一一排除后,发现几乎没有啥提高。
其实,在第二点缩小范围时,应该意识到,空白问题/拖动不流畅均是由于渲染性能低下
致使的
为了验证是Select 组件的问题,基于:
rc-virtual-list
作了一个在线 demo :
在线地址:https://codesandbox.io/s/opti...
动态演示:
这里渲染了1000 条记录, 每条记录里有5个select;
默认使用的是 antd Select, 几乎拉不动;
切换到原生select以后, 如丝般顺滑。
由此能够肯定,卡顿是 Slect 组件引发的。
因此要减小渲染成本:
基于 Intersection Observer
实现一个 下拉懒加载。
利用 Intersection Observer 实现:
在列表的底部(也多是底部偏上的某个位置)插入一个observer-dom元素.
经过Observer来观测其是否在可视区域中,若是在,那么就往下加载更多的内容:
初始状态时,列表会多渲染几条数据(两屏数据),observer-dom元素一直被顶到底部.
用户往下滚动时,observer-dom元素“出现”在用户视野。
每次多加载一屏的数据,循环如此,直到整个列表都渲染到页面上。
在线demo:
https://codesandbox.io/s/gund...
动态演示:
最终采用下拉懒加载。
一般,无限滚动的方案能够分为两种:
在选择虚拟长列表or下拉懒加载之间的取舍时,能够参考:
若是闪动问题能够接受(组件渲染没有太大性能问题),并且对dom数量要求很严格,那么选择虚拟长列表会更好。
若是闪动问题不能接受,而最终的dom数量可以接受,那么选择下拉蓝加载会更好。
不管是选择虚拟长列表or下拉懒加载,在使用监听scroll事件或者Intersetion Observer API之间的取舍时,能够参考:
而使用Intersetion Observer API,上述几点的计算就能够省略了,优化工做交给了浏览器。
若是不考虑IE 等, 它是一个不错的选择。
内容就这么多, 但愿对你们有所启发。
若有错误, 欢迎指正, 谢谢。