本文作者:段家顺
背景
随着 React Native 技术在业务中宽泛的利用,一些比拟重要的性能也开始采纳 React Native 的技术计划来实现,这就给 React Native 页面的关上速度提出了更高的要求,因为关上速度是影响用户跳出率的重要起因之一。
拆包
对于 React Native 关上速度优化,业界比拟通用的计划也就是预热 + 拆分根底包,缩小容器初始化工夫和根底库加载工夫。
对 React Native 进行拆包能够依赖于官网提供的工具进行,然而官网提供的能力是 JS 外部的一个拆分加载,如果咱们须要做容器预热,则无奈应用官网的加载计划,而须要咱们从客户端本来的逻辑中进行革新为多步加载。
咱们须要对 React Native 的逻辑进行革新,就须要对 React Native 初始化逻辑有所理解。
上图是一个大抵的过程,这里咱们对比拟要害的几个步骤进行简略的阐明。
- RCTBridge 在实例化之后,会首先筹备好 JS 运行线程和原生模块。
- 而后会创立一个 JSExcutor,这个执行器决定了 JS 执行环境是客户端还是近程调试(安卓能够是本人定制的执行器,比方 V8)。
- 加载源码(bundle),这个依据起源不同可能是从本地加载,也可能通过 url 从远端加载。
- 因为初始化 JS 执行器和代码是并行触发的,这里须要一个栅栏同步两者后果,之后开始将代码放入执行器执行(JS 代码运行)。
- 在此之后,客户端会监听垂直同步信号(该信号的作用是在页面产生变更的时候,须要从新刷新页面)。
- 此时 RootView 收到 JS 加载实现的告诉,开始触发 RunApp 逻辑,该逻辑就是启动前端的 app 注册表中对应的利用。
整个流程比拟长,然而分工还是相当明确的,此次拆包革新的中央也十分明确。
上图中绿色框内就是咱们此次革新的点,这里从实现简略与以后需要的角度登程,将加载代码设计为串行加载,如果须要进一步优化,加载过程也能够进行并发设计。
这里咱们对加载能力进行一次形象,加载一段代码定义为一个SourceLoader
,那么一个拆包 bridge 就相当于有一个加载器列表,对应于 bridge 上的属性就非常简单。
@property (nonatomic, strong) NSArray<id<RCTBridgeSourceLoaderProtocol>> *preloadSourceLoaders; // 预加载的加载器
- (void)preloadSourceWithCompletion:(void(^)(NSError *error))completion; // 触发预加载加载器
@property (nonatomic, strong) NSArray<id<RCTBridgeSourceLoaderProtocol>> *sourceLoaders; // 非预加载加载器
- (void)loadSourceWithCompletion:(void(^)(NSError *error))completion; // 触发非预加载器
- (void)loadAllSourcesWithCompletion:(void(^)(NSError *error))completion; // 先加载预加载代码,再加载非预加载代码
这里有一个须要留神的点是,咱们须要启动一个垂直同步信号监听,为了性能思考,须要在预热容器加载到真正视图的时候能力开启,所以这里对加载器减少一个标记,只有加载到该加载器之后能力开启监听。
通过这样的革新,咱们的 React Native 就曾经反对了多包散布加载了。咱们就能够把一些根底性能的 JS 代码打包进利用外部,也缩小一些包大小。
容器预热
只有分包加载并不能对加载速度有太大的影响,而真正的优化点是容器的预热。预热能够将很多筹备工作先做了,在业务加载的时候只会触发加载业务代码与渲染页面。
受限于手机性能的局限,以及一些苹果官网的策略,咱们不太可能无限度的去应用该能力,所以这里按 3 个方面来看预热。
预热触发机会
目前预热触发的机会次要有上面 3 个点
- 冷启动
- 热启动
- 容器复用之后
在这些机会触发之后,再提早肯定工夫(5 秒),进行创立预热实例。提早一会的起因是这些机会大概率都是在做一些 CPU 密集型工作,如果此时再退出创立预热容器这种非必须的工作,反而可能影响主业务的一些性能。
预热容器销毁
目前销毁的机会次要有上面 2 个
- 内存正告
- 进入后盾
进入后盾销毁的目标次要是为了升高后盾运行的内存,尽管这点内存占比不大,然而目前苹果对后盾运行的策略还是比拟严格的,所以咱们尽量减少存在的影响。
预热的场景化
因为 React Native 这种能力在咱们的业务中并不负责次要场景,可能大部分用户都不会应用到 React Native,而咱们对全量用户进行无差别的开启预热性能,也不是一种最优的形式。目前咱们还没有能力对用户场景进行机器学习这样的智能化剖析,那么这次就对一些场景做一下简略的归类:
- 3 天内没有应用过 React Native 能力,则认为该用户后续也不会应用该能力
- 3 天内没有因为内存正告而销毁的记录
-
以后利用启动周期内:
- 预加载失败 3 次,则该周期内不再启用预加载
容器预热的关键点是在不影响用户其余体验的时候,尽可能的进步预热的命中率,目前做的一些策略都比较简单,后续如果要优化,就须要深刻业务场景中。
成果
当开启拆包和预热能力后,商城页面包大小从整包 1.1M 缩小为 856K,页面关上时长在 iOS 里由 450ms 缩小到 200ms 左右,在安卓里由 4500ms 缩小到 2500ms,双端的优化成果都非常明显,阐明咱们的优化计划是十分无效的。
总结
此次 React Native 的优化分为拆包和预热两局部,各自能力独立,并别离进行 AB 管制,最大可能保障稳定性。后续将会深刻业务场景去做一些优化策略。
本文公布自 网易云音乐大前端团队,文章未经受权禁止任何模式的转载。咱们长年招收前端、iOS、Android,如果你筹备换工作,又恰好喜爱云音乐,那就退出咱们 grp.music-fe(at)corp.netease.com!