背景

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

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

今天就给大家分享一下。

正文

场景描述

用户需要批量修改 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/optimistic-bartik-69ygc?file=/src/animation.tsx

动态演示:

这里渲染了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/gundongjiazai-antd491-forked-vtchw?file=/index.js

动态演示:

选择方案

  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 等, 它是一个不错的选择。

内容就这么多, 希望对大家有所启发。

如有错误, 欢迎指正, 谢谢。

acrobat 下拉列表 逻辑_记一次 无限列表 滚动优化相关推荐

  1. jq 下拉加载每次只执行一次_记一次 无限列表 滚动优化

    背景 长列表优化, 是页面性能优化中的一个比较常见的问题,也是面试中的常客. 刚好最近在的项目中, 遇到了一个长列表的性能问题,试过多种方案, 最后得以解决. 今天就给大家分享一下. 正文 场景描述 ...

  2. element下拉列表触发_记一次vue长列表的内存性能分析和优化

    好久没写东西,博客又长草了,这段时间身心放松了好久,都没什么主题可以写了 上周接到一个需求,优化vue的一个长列表页面,忙活了很久也到尾声了,内存使用和卡顿都做了一点点优化,还算有点收获 写的有点啰嗦 ...

  3. pythonweb接口优化_记一次 Python Web 接口优化

    优质文章,第一时间送达! 作者:Lin_R 出处:SegmentFault 背景 我们负责的一个业务平台,有次在发现设置页面的加载特别特别地慢,简直就是令人发指 让用户等待 36s 肯定是不可能的,于 ...

  4. code blocks代码性能分析_记一次Python Web接口优化,性能提升25倍!

    背景 我们负责的一个业务平台,有次在发现设置页面的加载特别特别地慢,简直就是令人发指 让用户等待 36s 肯定是不可能的,于是我们就要开启优化之旅了. 投石问路 既然是网站的响应问题,可以通过 Chr ...

  5. flutter 卡顿_记一次flutter列表卡顿的优化

    在做滑动列表时通过profile发现GPU和FPS一直爆红.打包出来的应用滑动也很卡. 原因:频繁调用setState造成的.自己的粗心大意导致的.列表需要根据滑动的高度显示一个返回顶部的按钮.所以用 ...

  6. excel下拉列表数据筛选_从筛选的Excel列表中下拉

    excel下拉列表数据筛选 Someone asked me how to make a data validation drop down that only shows the visible r ...

  7. excel下拉列表联动_动态数组的Excel下拉列表

    excel下拉列表联动 Select a region name in one Excel drop down list. Then, in the next drop down list, sele ...

  8. excel下拉列表联动_国家和城市的Excel下拉列表

    excel下拉列表联动 In Excel, you can use data validation to create drop down lists on a worksheet. Usually, ...

  9. 学习笔记_记一次植物大战僵尸的破解

    学习笔记_记一次植物大战僵尸的破解 1.学习目标 2.学习工具 3.开始操作 3.1 理清思路 3.2 开始操作 4.总结 1.学习目标 了解二进制.十六进制对于计算机的意义 掌握二/八/十/十二/十 ...

最新文章

  1. php的安装配置,PHP 安装/配置
  2. spring AOP编程
  3. linux 使用退格键时出现^H解决方法
  4. 使用IDA PRO+OllyDbg+PEview 追踪windows API 动态链接库函数的调用过程
  5. 读操作系统的设计与实现--进程互斥
  6. visual studio过期登录不了账户_具有最高管理权限账户,Windows 7设置Administrator密码永不过期...
  7. 飞鸽传书认证是互联网界具有极大声望
  8. leetcode142. 环形链表 II
  9. java类路径定制_设置Java类路径的注意事项
  10. python文本筛选html,从html页面的列表元素中筛选数据
  11. mysql自连接_深入理解mysql的自连接和join关联
  12. ActivityGroup对子Activity的管理
  13. vue下载文件常用的几种方式
  14. excel退出打印预览快捷键?
  15. Scanport(转来备用,在那小子以后攻击我的时候用)
  16. pg_bigm 处理中间模糊匹配 like ‘%xxoo%‘
  17. 香肠派对显示服务器断开怎么解决,香肠派对闪退如何解决 闪退解决方法
  18. C语言中用单引号括起多个字符的问题
  19. PHP自适应小说网站源码深度SEO优化自动采集
  20. C++中怎么表示根号下的数字(用cmath中的sqrt()可以开根号)

热门文章

  1. 【Redis】杂项基础知识;Redis数据类型
  2. C# 什么是【事件驱动】
  3. C语言:以scanf的使用为例,对缓冲区的理解
  4. 小师妹学JVM之:cache line对代码性能的影响
  5. emui与华为鸿蒙关系,华为王成录谈鸿蒙和EMUI的关系
  6. 【MySQL性能优化】MySQL分库分表与水平分割取模案例(三)
  7. 容器源码分析之PriorityQueue(十)
  8. Netty私有栈协议
  9. WebService开发方法介绍
  10. 区块链技术指南笔记(一):区块链基本概念