likes
comments
collection
share

记录一次组件性能优化的解决过程

作者站长头像
站长
· 阅读数 22

一、背景

项目迭代期间,有个比较常用的React组件发现有性能问题,leader叫我看看。开始还是比较紧张的,因为这是公司平台的一个基础组件,各个团队都有可能会用,有点担心给改坏了,性能问题给改成了问题。这个组件是一个类似穿梭框的组件,将左侧的待选数据选择增加到右侧的已选数据。

二、问题记录

在点击单个数据时,只有一条数据增加到右侧选中区,体验良好。 在点击全选按钮时,将左侧列表全部数据增加到右侧选中区。在数据量为300左右时,耗时大概是90s,迟滞感明显。 这个性能问题可以稳定复现。

三、问题排查

  1. 在源码中找到 全选操作的回调函数,按照全选操作执行的调用链依次排查。 (具体的代码就不贴出来了,抽象成逻辑来分析)。

记录一次组件性能优化的解决过程

  • 点击全选按钮,调用 selectAll 函数

    • 循环遍历 selectAllData ,将数组的每一项 作为参数 传入 B 函数,向外部抛出
  • 调用 B 函数

    • 调用 C 函数

    • 判断传入的数据项是否可以增加

      • 可以增加,全选选中的数据项 和 已选中的数据 合并作为 新的已选中的数据,并调用setState重新设置已选中的数据。
      • 不可以增加,不作操作。
  • 调用 C 函数

在全选操作执行的调用链中,可以发现,主要的逻辑都集中在 B 函数中,全选时选中的数据有多少项,B 函数就会执行多少次。

每次执行 B 函数,都会调用 C 函数,都有可能调用setState修改状态并进行重新渲染,这就导致全选操作的耗时随着数据量线性增长。

导致性能问题的原因主要有两个:

  1. 新增数据的每一项都会调用 appendItem 函数,有可能修改state进行重新渲染

  2. 每次调用 appendItem 函数都会调用 resetSearch 函数 来重置搜索相关的逻辑

为什么其他情况没有暴露出性能问题:

在点击单个数据进行选择的时候,只会调用一次 B 函数,单次操作耗时比较少,用户基本无感知。

四、优化方案

优化思路:

针对导致性能问题的主要原因,在结合具体的需求和交互,做出以下优化

  1. 全选时,先将 全选选中的数据 和 已选择的数据 进行 去重合并,再用得到的新数据更新 state。

(将多次的setState合并成一次。)

  1. 在设置完新的state之后,再调用 C 函数。

(从交互上来说,原有交互是在点击某个选项时会新增到已选择数据并重置特定逻辑,在统一设置完新的state后再重置特定逻辑符合原有的交互。)

具体实现:

新增了一个props onSelectAll,在点击全选时将全选全选选中的数据整体向外抛出

记录一次组件性能优化的解决过程

五、优化结果

指标优化前优化后对比
数据量278条278条
耗时90s2s耗时减少97%(粗略)
Google Chromeperformance记录一次组件性能优化的解决过程记录一次组件性能优化的解决过程

从 performance 的分析来看。

CPU的图形分布中,script 的执行时间占比较大,可以初步判断是script的执行消耗了大量的资源。

火焰图中存在大量的近似的起伏,有可能是大量的重复调用。

六、总结

1. 性能问题的排查思路

这里主要是指代码逻辑层面

  • 找到触发性能问题的场景,依照操作执行的调用链依次排查

  • 性能问题分两种:

    • 不可用(资源耗尽,爆栈):是否存在无限循环,循环调用......

    • 可用(只是单纯的慢):代码逻辑是否合理,是否存在冗余操作,执行和渲染,重复的操作在逻辑上是否可以进行合并......

2. 工具

  • 朴实而万能的 console
  • Google Chrome performance
  • 好像还有一些专业的性能测试工具,但是还不太会用哈哈哈
转载自:https://juejin.cn/post/7155071103696633886
评论
请登录