列表数据量大,在mac上无法打开问题记录

17 阅读3分钟

一、现象

小程序大列表在windows上可以使用,在mac上列表渲染白屏。

1.png 2.png

二、分析

数据量小环境可以正常使用,可以排除业务逻辑的问题。与其他环境差相比,排查出无法渲染的环境与其他环境数据量不在同一个数量级,可以确定是代码的某个地方处理存在性能瓶颈。

环境数据量
开发(无法渲染)34 * 401
测试(可渲染)4 * 5
仿真(可渲染)3 * 10
生产(可渲染)5 * 5

经过一系列的测试,可以定位到出问题的代码是如下红框中圈出的部分

3.png

三、方案探索

  1. 这部分代码中比较明显的是扩展运算符(...)的性能问题,扩展运算符(...)与传统的对象方法Object.assign和数组的合并方法concat相比,存在非常明显的性能差异,从下图可以看出,在处理大数据方面,传统方法的性能远远好于扩展运算符(...),以下测试数据是10w左右的一维数组,具体测试细节详见:juejin.cn/post/701744…
image.png

顺着这个思路做的第一个改动抛弃扩展运算符,采用传统的方式进行对这部分代码进行改写

4.png
  1. 改完测试发现并不生效,且进一步测试发现,只要存在如下代码,后续的状态更新都不生效(在页面上展示currentIndex和afterCode都不是最新值),从而定位到数据量大、数据结构较为复杂的情况下,setData的性能瓶颈在MAC上被触发。
this.setData({
	todoData: _load.todoData
});

// 以下代码不生效
this.setData({
    currentIndex,
    afterCode,
});

进一步分析发现,除了在事务中心page页存在多次更新todoData,在其子组件List中,还存在对其进行二次加工生生成viewList和dropdownData,分别用来渲染列表和筛选器,这就导致了更加严重的性能问题。

  1. 尝试优化todoData数据结构,并试图减少数据量进行测试,结果发现即使删掉了很多不用的属性,且最大数据量只有34 * 50的时候依然没有办法正常渲染列表。
  2. 采用微信小程序提供的recycle-view(长列表)组件重构这部分代码,recycle-view主要用来解决如下问题:
  • 列表数据很大,首次 setData 的时候耗时高
  • 渲染出来的列表 DOM 结构多,每次 setData 都需要创建新的虚拟树、和旧树 diff 操作耗时都比较高
  • 渲染出来的列表 DOM 结构多,占用的内存高,造成页面被系统回收的概率变大。

其核心思路是通过createRecycleContext方法创建RecycleContext对象来替代 setData 管理数据,并且只渲染显示在屏幕的数据,不需要渲染的数据留一个空的 div 占位元素。采用recyle-view重构的效果是在mac上可以正常打开,滚动加载更多也是没有问题的。

5.png

四、结论

  1. recycle-view可以解决mac无法打开复杂数据大列表的问题(原因:setData管理数据存在性能瓶颈)
  2. recycle-view相较setData,在性能方便有很大的提升,如果采用此方案可以从一定程度上提列表的渲染速度,提升用户体验
  3. recycle-view只能在page中使用,不能再component中使用

注: 模拟器性能相较真机较差,在较新的手机上现有方案并没有模拟器上如此明显的延迟效果。