RN 启动简介
Dive into React Native performance
阐述了基于RN实现的页面各部分加载时间占比图
页面加载流程图(引用)
从业务视角可以归纳为四个部分
- Bundle包准备:客户端Bundle包下载、解析等过程
- 初始化引擎:引擎准备,RN执行环境
- 加载Bundle:引擎加载JS代码
- 渲染Bundle:执行JS中runApplication()方法,开始渲染
RN 启动优化实践
包生产
- 分包
- 分业务分包:页面维度单独成包,避免大文件包
- 分层分包:页面和组件拆分,便于复用,同时也减少了整体体积
- 拆包
- 一种方案,将一个包整体的index.js,拆分成一个入口+多个子模块,从而实现页面模块维度懒加载功能,减少页面首次加载时间,webpack和react loadable都有提供了切割能力
- 另一种方案,RAM bundles和内联引用
- RAM bundles:Indexed RAM Bundle和File RAM Bundle两种实现,将每个模块拆分为独立文件
- 内联引用(inline requires):内联引用(require 代替 import)可以延迟模块或文件的加载,直到实际需要该文件。
- 包大小优化
- 包大小分析工具
- 引入tree-shaking将无用代码删除
- 静态资源压缩,重点图片
包下载
- Bundle包缓存策略优化,减少下载时间
- 核心或者重要页面直接预装
- 本地增量更新策略
- Bundle包下载策略优化,根据页面深度区分下载时机,实现延缓下载,减少首次并发下载任务量
包加载
- 业务容器层加载JS的引擎,使用引擎池技术,默认空引擎+引擎复用,减少引擎池初始化时间
- 底层引擎可以根据业务进行替换,使用V8或者Hermes React Native Memory profiling (JSC vs V8 vs Hermes
包渲染
- 数据层
- 本地化数据优化,数据缓存、前一个页面数据带入后一个数据
- 数据请求异步加载,且尽可能提前请求,譬如执行js加载到内存
- 模块层
- 模块=页面一个个模块,对于复杂或者长的页面,简单理解可以是预先加载可见模块,然后在加载非可见模块。
- 组件层
- 减少重复渲染,例如pureComponent、Immutablejs、 列表 & Key、慎用setState
- 其它React布局和渲染的一些常规优化
列表
官方推出的FlatList及SectionList的一些问题
- 元素懒加载:元素只有出现在屏幕中,才会被初始化出来。
- 无复用池机制:且初始化后不销毁:在元素离开可视范围后,会被同尺寸的空白元素替换,但是不会被销毁。另外FlatList中item的viewTree并没有真实复用,随着滚动渲染出来的viewTree越来越多,内存开销过大容易出现OOM
- 异步渲染:在空白元素滚动到可视区域后,会进行UI渲染,先创建了一个等高空白容器,然后整个cell的viewTree异步渲染完成后再添加到空白容器内。所以快速滑动的时候,由于异步任务堆积,导致无法快速展现出现白屏。
官方对列表的一些配置推荐和实现建议 Optimizing Flatlist Configuration
- Props
- maxToRenderPerBatch,最大预加载数,即屏幕外渲染的Item数目
- updateCellsBatchingPeriod,批量更新Cell周期,即批处理更新时间频率
- initialNumToRender,初始化最大渲染数
- List Items
- 尽可能使用基础组件、轻量化组件,Item尽可能低层级、少逻辑
- 使用shouldComponentUpdate来优化diff判断,从而减少重复渲染
- 图片控件缓存优化,例如推荐react-native-fast-image优秀的图片控件
- 通过getItemLayout告知高度,减少layout时间
- 使用 列表 & Key,加速更新Diff计算
- 避免匿名函数,每一个函数是一个新的对象
列表实践过程中的思考
OOM(增加复用能力)
实现Cell复用:一种思路是Native列表 + RN Cell,借助Native列表实现Cell复用能力,需要做以下几个事情
- Native列表渲染Cell,在没有RN Cell的时候需要占位,有Cell的时候需要展示
- Native列表Cell复用情况下,需要复用正确RN Cell,Cell之间关联关系处理
- Native渲染线程全部在主线程同步执行,但是RN渲染是经过JS -> Shadow -> Native 三条线程异步操作,所以需要主动进行通信机制管理
白屏(减少通信或者提高通信速度)
Native与RN通信频繁是带来白屏的主要原因,那么可以结合一些特定的业务场景进行一些优化
- 新一代的RN重构框架Fabric会重点优化线程通信效率,敬请期待
- RN侧自己感知View变更,作出更新操作,而不全依靠Native通知,从而减少通信。例如顶部、底部上下移动带来新的View渲染,点击回到顶部,直接服用首页View等RN侧处理操作
- 快速滑动限速,一般来说快速滑动是一个非常规操作,我们可以将速度限制到合理范围,减少过多的异步任务并发出发
参考:
React Native之启动流程
Tree-Shaking性能优化实践 - 原理篇
ReactNative 性能