Skip to content

React Native大数据列表优化经验

石破天惊 edited this page Jan 29, 2018 · 2 revisions

前言

  • 原生级的性能体验
  • 一次代码,多端共享
  • 修改代码立即可见修改所得
  • 热更新

当我第一次使用react native开发的时候,深深地对这几点所吸引,在目前的互联网高速迭代的时代,它无疑拥有极大的价值。(当时苹果上架审核每次必然7天)一路磕磕盼盼地走来,当我们将它应用到实际项目中才发现许多问题,其i中最大的问题就要属大数据列表的性能问题了。虽然号称原生级的性能体验,其实在大数据快速列表中,性能也是相当的不如意的。作为一个iOS原生App开发人员,其实我一直天真地以为这只是一个bug,等到后续版本了,官方必然能将之修复。后来才知道,对于一个JavaScript实现的应用来说,能达到这种性能来说,已经是很很好很好了。网页上基本不可能有那么快的滑动速度,也不会一直展示那么多内容。在之后的很长一段时间里,官方的FlatList/SectionList性能并没有很大的改善,官方也并没有打算继续能有多大的改善。

于是,我就展开了react native大列表的优化之路:


优化之路第一步:暴力原生桥接(iOS)

说到性能优化,我毫无悬念地想到原生优化。为此,我先在iOS上努力。首先我在原生里面导出一个View,把一个UITableView添加进去,拦截react native添加到本View的子元素,并全部添加到UITableView中。这样也不是没有用,滑动的时候性能是提升上去了,无论你滑动再快也不会出现空白,但是初始化的时候创建了太多View。 如果数据源特别多(比如1000条),初始化的时候会花到3-5秒时间,并且内存占用相当大。后来我才发现,这样的改造,有人已经做过这个工作了,这个三方的库就是这样做的 react-native-tableview

优化之路第二步:重用的原生桥接(iOS)

第一步完成以后,我感觉到了,这个是有意义的。所以进入下一步,重用以减少初始化时间和内存占用。 这一步改造我走了很多弯路,花费太多时间。最初,我一直纠结重用机制是写在JS端,还是Native端。经过多番确认得到如下结论:

  • 通过setState重新渲染会全部暴力地全部重新渲染所有子节点,效率相当地下
  • react native不通过重新渲染是无法向某个节点直接添加子节点的

为了避免频繁的创建子元素,在初始化的时候我创建一个比较大的Cell池,每个Cell打上一个由section和row算出来的tag传入原生,原生端在- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;中从Cell池中寻找正确的tag,并将它从父视图移除,添加到当前的UITableViewCell当中。