原栏目|居玉溪

Qunar.com移动建筑集团前端工程师。从事平台技术服务设施建设,库纳react Native的开发者主要负责现阶段统一解决方案Ykit的前端建设。

欢迎来到团队博客ymfe.tech,了解更多关于尖端技术的信息。

过去一年,去哪儿大规模应用React Native(简称RN)。结合业务本身的需求,我们基于RN-去哪儿React Native(简称QRN)提供了一套更适合去哪儿的解决方案。它包括公共包和业务包的拆分,组件和API的重新打包,以及各种提高开发效率的插件。

对于移动设备上的长名单,首屏渲染速度和内存恢复一直是我们关注的问题。ListView是RN提供的列表组件,类似RecyclerView和UITableView,采用渐进式渲染。也就是说,仅呈现用户可视区域中的元素,并且可视区域中的元素根据位置偏移来更新。

1.React Native ListView性能优化实践1.1 RN ListView实现原理

RN ListView与RecyclerView、UITableView在无尽列表处理上不同,即没有真正的复用节点,只是将元素从其父组件中移除出视口,从而释放内存。移除的元素将仍然存在于虚拟树中,并且列表中每个项目的引用将被保存。

上图显示了RN ListView在第一屏和渲染到100行时的元素统计。红色方框中标记的数字,上面一个代表可视区域中的元素数量,下面一个代表虚拟树中的元素数量。可以看到,从第一屏到100行,虚拟树中的节点随着新元素的渲染而增加。

RN ListView的主要目的是保存每行的状态,加快渲染元素的重渲染。这一点在克里斯托弗·切多(RN的核心开发者之一)身上已经说得很清楚了。

1.2 rn listview的性能如何

这里我们从滑动体验、记忆占用、位置跳跃能力三个方面来评价RN ListView的表现。

在滑动体验方面,我用上图中的列表在iPhone 5S中进行测试。RN ListView的帧数基本可以保持在55~60 fps,一般比较流畅。

和前面的例子一样,在内存占用方面,从上表可以看出,随着列表内容的不断增加,其内存占用迅速增加。在无尽列表的场景中,应用程序可能会因为过度占用内存而崩溃,这是我们无法接受的。

位置跳转的能力是指在某些场景下,列表需要瞬间跳转到某个位置,比如通过通讯录中的首字母跳转。在RN ListView中,由于布局系统是由RN控制的,所以需要知道每一行从起点到终点的高度,才能准确的渲染出指定的位置。所以跳转到未知区域时,必须先渲染起点和终点之间的所有元素,会造成一段时间的白屏,所以RN ListView在这个场景中的体验不够好。

1.3 qrn listview是如何优化的?1.3.1 QRN列表视图原则

为了解决注册护士列表视图的性能问题,我们引入了QRN列表视图。它不采用与RN ListView相同的维护元素引用的方式,而是在React渲染列表时通过虚拟树机制实现元素重用。

首先,介绍了如何使用React渲染列表:React要求列表中的每个项目都有一个关键属性,该属性将在React的虚拟树diff过程中用作每个项目的标识符。

在上图中,我们假设包装器是列表的容器,组件是列表中的一个项目。当列表从左状态切换到右状态时,React会认为键为{1}的项目已被移除,键为{6}的项目已被添加,因此总共执行了一次销毁操作和一次创建操作。

我们稍微修改了一下前面的情况(如上图)。此时,React会认为key={1}的项目已经改变了位置,所以只会更新它,从而达到重用我们节点的目的。

按照这个思路,QRN的具体实施如上图所示。当一些项目移出可视区域时,它们的键被分配给要创建的行。

1.3.2 QRN列表视图性能

这里我们还是从前面三个方面来评价QRN ListView的表现,即滑动体验、记忆占用和位置跳跃能力。

根据相同条件下iPhone 5S中的测试结果。QRN ListView的帧数在30~40 fps左右。经过调查,我们发现影响性能的主要原因是16 ms内渲染一帧时间过长。

在内存占用方面,从上表可以看出,随着列表内容的增加,QRN ListView的内存基本稳定。RN ListView内存增长太快。

和RN ListView一样,它需要知道起点和终点之间每一条线的高度,才能准确的渲染出指定的位置。所以QRN ListView在这种场景下的体验是不够好的。

1.4特定场景的优化-qrn无限列表视图

由于RN的布局机制,无法从纯JS层面完美解决位置跳转,所以我们决定针对具体场景进行优化。通过与实际业务应用的接触,我们发现列表组件主要有两种使用场景。

一种是上图左侧的情况,每一行的行高可能是不确定的,通过用户连续滑动逐渐加载新内容,一般不会出现跳转到还没有渲染的位置的情况。另一种是右边的情况,通常是通讯录或者城市列表。每一行的高度都是固定的,需要有按位置跳的能力。

因此,我们在固定行高的场景中提出了一个深度优化的QRN InfiniteListView组件。

1.4.1固定高度场景可以做哪些优化?

在可变高度的情况下,渲染一条线时,必须先渲染前一条线并获得其高度和位置,然后才能继续渲染。但是,固定高度列表可以同时在多行中呈现和重用。原理如下:

1.4.2 QRN InfiniteListView性能

QRN InfiniteListView的性能还是从以上三个方面来评价的,分别是滑动体验、内存占用和位置跳转能力。

根据相同条件下iPhone 5S中的测试结果。QRN InfiniteListView的帧数可以保持在55~60 fps。所以可以说帧率比QRN ListView有了很大的提升。

在内存占用方面,从上表可以看出RN InfiniteListView的内存增长缓慢。由于QRN ListView和QRN ListView一样,采用了元素复用的方式,所以内存恢复取得了很好的效果。

在位置跳转方面,由于每一行的高度和位置都可以通过计算直接得到,所以滚动到任意位置都可以正确的呈现内容。

1.4.3场景的扩展

即使在一些高度不等的场景中,行高也是可以确定的,比如一个只有几类内容的列表。此时,我们可以通过一个界面来指定行高。

1(rowData, rowIndex) => number

所以InfintiteListView可以覆盖除行高完全未知以外的大部分列表场景。

1.5总结

通过比较上述三个列表组件,我们可以得出结论,QRN InfiniteListView最符合我们的性能要求,但它仅限于特定的场景。但也给了我们一个性能优化的思路,就是当我们不能考虑所有的平台和场景时,可以针对一些特定的场景进行优化。最近在继续优化列表组件,会提供更好的解决方案,会继续关注列表性能。

1.《listview的优化 【YMFE】React Native ListView 性能优化实践》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《listview的优化 【YMFE】React Native ListView 性能优化实践》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/jiaoyu/1607148.html