背景

在实现说说列表功能时,只想到了实现具体业务,没有考虑到长列表对性能的影响,每个说说组件都包含了复杂节点结构,大量的事件处理程序和动画等,每当加载新的一页时会造成组件累积,占据大量内存,在安卓中的表现是滑动极其卡顿,在ios中的表现是加载2、3页左右会出现小程序崩溃的情况,当快速滑动时小程序会黑屏。

解决思路

导致崩溃、黑屏的原因经分析是因为内存占用过高,而导致内存占用过高的原因是因为说说组件累积,当加载新的一页时,前面的说说虽然已经不在需要,但是仍然会保留在内存中,对于移动端这种对内存限制要求高的设备会造成性能影响,因此最根本的办法是使用虚拟列表技术优化说说列表。

采用说说列表的核心思路是采用双数组的方式,一个数组存放所有说说,另一个数组存放需要被渲染的说说,以此来达到释放不再需要的说说组件的目的。但是要实现虚拟列表需要解决两个问题:

  1. 怎么知道哪些说说组件应该被显示?哪些应该被释放?
  2. 如何避免因前面的说说组件被释放而导致页面抖动的问题?

优化方案

第一次(页面滚动+偏移量计算)

思路

采用页面滚动监听+定位的方式实现。通过监听onPageScroll事件来获取滚动量,从而判断当前屏幕中应当出现哪些说说,但是这里有个问题每个说说组件的高度是不确定的,比如有些说说有9图片,高度就比普通说说高,因此不能直接计算说说的总高度与页面滚动量对比,这里的解决方法是为每个说说组件设置最小高度和偏移量,通过提前预判图片数量、文字个数来确定偏移量,也就是说说说的高度是最小高度+偏移量。

另外当前面说说组件释放后,由于页面流的作用,当前屏幕的说说会“塌陷上去”,造成窗口抖动,预想的解决方式是为第一条渲染说说设置定位,上面说说被释放的同时立刻计算第一条渲染说说应该出现的位置,然后通过position: relative + top来设置定位,避免“页面塌陷”。

结果

采用此方案后

通过定位来防止窗口抖动很难实现,因为非常难计算

onPageScroll事件触发太频繁,对性能消耗太大,此外在此事件进行大量计算可能会导致页面卡顿。

固定说说高度体验非常不好,而且偏移值难以计算,还容易出现bug,也不方便功能扩展。

第二次(空白盒子+节点查询)

思路

分析第一次失败的原因,原因有二:

  1. 1.最小高度+偏移量来确定说说高度不具有可行性,首先是计算复杂,其次也不方便功能扩展。
  2. 2.通过定位无法阻止窗口抖动,因为计算得来的高度很容易出现误差,哪怕与实际高度只有一点差距,都会造成窗口抖动。