关于前端:????-记一次-无限滚动-列表优化

背景

长列表优化, 是页面性能优化中的一个比拟常见的问题,也是面试中的常客。

刚好最近在的我的项目中, 遇到了一个长列表的性能问题,试过多种计划, 最初得以解决。

明天就给大家分享一下。

注释

场景形容

用户须要批量批改 Product中 sku 的 映射关系,能够抉择的 Product 的 数量不限

每一条sku 对应如下构造:

因为能够抉择的sku数量是不限的, 又不能分页, 只能做到一个列表里。

于是, 长列表呈现了。

刚开始的计划是做一个虚构列表

具体就是通过监听sroll事件,每次滚动后计算个别元素地位(top和height)

而后,通过渲染三屏的形式,把一段数据渲染到页面上。

数据量不多的时候, 没什么问题。

当抉择几百上千条sku 的时候, 疾速滑动, 就开始呈现卡顿。

如图所示:

作为比照,看一下优化后的成果:

问题定位

在chrome调试工具下,边拖动列表边察看dom的变动。

发现,dom的卸载/挂载/更新的状况都出奇地慢,鼠标曾经停下来,能显著感觉到过一会dom才装载实现,所以很可能是dom的渲染性能问题。

定位到渲染性能有问题的dom身上,即每一个 Item(renderFakeTable)。

应用一般文本代替Item,在同样多数量的列表状况下,简略的dom显著会顺畅很多,然而,依然会呈现空白问题。

持续察看renderFakeTable中的每一个元素(能够借用devTools Profiler)。

最简略粗犷的形式就是去除某一类的组件,而后通过一直自测的形式,找出最有可能影响渲染效率的元素:

SearchSelect(基于antd的Select封装的一个业务组件)。

所以,影响渲染性能的元素很可能就是它。

渲染性能

除了组件的问题,还有可能是渲染的问题。

首先,原来有限滚动的逻辑就是基于scroll事件,通过一直滚动触发的回调,从新计算渲染到页面上的区间。

其次,为了动静调整可视区域的元素,应用了MutationObserver。

导致空白问题则会有这几种可能:

  1. 没加防抖,频繁渲染带来性能耗费
  2. scroll 和 MutationObserver 相继执行了渲染,导致dom呈现了跳动的景象。
  3. 预留的元素个数,viewPrepareCount太小了,导致拖动太快时,前面或后面都没有多余的可见元素
  4. 没有开启GPU减速,应该应用transform代替top来定位到正确地位

不侥幸的是,以上的可能都一一排除后,发现简直没有啥晋升。

其实,在第二点放大范畴时,应该意识到,空白问题/拖动不晦涩均是因为渲染性能低下导致的

测试验证

1. 虚构列表 rc-virtual-list

为了验证是Select 组件的问题,基于:

rc-virtual-list

做了一个在线 demo :

在线地址:https://codesandbox.io/s/opti…

动静演示:

这里渲染了1000 条记录, 每条记录里有5个select;

默认应用的是 antd Select, 简直拉不动;

切换到原生select之后, 如丝般顺滑。

由此能够确定,卡顿是 Slect 组件引起的。

所以要缩小渲染老本:

  1. 缩小本人的父组件渲染老本,React.memo/React.useMemo/React.useCallback.
  2. 缩小Select渲染老本(比拟麻烦,而且成果不显著。通过自测,仅仅是应用一个根底的Select,rc有限滚动的状况下同样产生了卡顿)

2. 下拉懒加载

基于 Intersection Observer 实现一个 下拉懒加载。

利用 Intersection Observer 实现:

在列表的底部(也可能是底部偏上的某个地位)插入一个observer-dom元素.

通过Observer来观测其是否在可视区域中,如果在,那么就往下加载更多的内容:

初始状态时,列表会多渲染几条数据(两屏数据),observer-dom元素始终被顶到底部.

用户往下滚动时,observer-dom元素“呈现”在用户视线。

每次多加载一屏的数据,循环如此,直到整个列表都渲染到页面上。

在线demo:
https://codesandbox.io/s/gund…

动静演示:

抉择计划

  1. 要么承受应用rc有限滚动的不够晦涩;
  2. 要么应用 Intersection Observer 实现一个下拉懒加载的有限滚动成果

最终采纳下拉懒加载。


总结

通常,有限滚动的计划能够分为两种:

1. 虚构长列表

  • 长处:能够保障渲染在页面上的dom元素尽可能少
  • 毛病:如果没有非凡解决(比方rc或锁定滚动区域),疾速滚动时,根本都会有闪动的状况(也就是本次的空白问题)

2. 下拉懒加载

  • 长处:避免用户疾速拖动的呈现闪动问题。再通过加一个loading成果,帮忙优化体验
  • 毛病:当用户把列表拉到底,整个列表都会被渲染到页面上

在抉择虚构长列表or下拉懒加载之间的取舍时,能够参考:

如果闪动问题能够承受(组件渲染没有太大性能问题),而且对dom数量要求很严格,那么抉择虚构长列表会更好。

如果闪动问题不能承受,而最终的dom数量可能承受,那么抉择下拉蓝加载会更好。

无论是抉择虚构长列表or下拉懒加载,在应用监听scroll事件或者Intersetion Observer API之间的取舍时,能够参考:

  • scroll的事件回调会在主线程中被成千上万次调用,只管加了防抖
  • scroll的形式,须要一直记录scrollTop和元素高度

而应用Intersetion Observer API,上述几点的计算就能够省略了,优化工作交给了浏览器。
如果不思考IE 等, 它是一个不错的抉择。

内容就这么多, 心愿对大家有所启发。

如有谬误, 欢送斧正, 谢谢。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理