2.3 启动流程与双端生命周期


2.3 启动流程与双端生命周期

本节摘要:启动是从点击图标到首屏可交互的全过程,中间经历原生壳初始化、引擎装载字节码、包执行、首次渲染五个阶段;生命周期则是应用在前后台切换时两端各自发出的一套事件,RN 用统一的 AppState 把它们映射起来。本节先定义「启动完成」再拆阶段,然后给出生命周期的双端对照表与资源释放的代码范式——这两块知识是第 8 章启动优化与热更新、第 4 章内存治理的直接前置。

先说清楚「启动完成」指什么

讨论启动性能最容易踩的坑是口径不一:有人拿白屏结束算,有人拿首帧渲染算,用户却只认「能点了」为准。本节的口径是三段式:启动时长等于原生壳就绪、引擎与包装载、首屏可交互三段之和。拆开讲,第一段是原生壳初始化——操作系统拉起应用进程,iOS 侧执行应用代理的启动方法,Android 侧走应用与应用活动的创建流程,初始化原生运行环境;第二段是引擎与包装载——Hermes 引擎启动并加载预编译的字节码(这正是 0.70 起 Hermes 成为默认后启动提速的主因:字节码免去了运行时解析 JavaScript 源码的开销),随后 JS 包开始执行,模块系统按依赖关系初始化,新架构下 TurboModules 让这一步从「全量注册」变成「按需装载」;第三段是首屏可交互——React 完成首次渲染,描述经渲染管线变成真实原生视图,布局绘制完成,用户手势开始有响应。

三段口径的价值在于定位:白屏时间长而首屏快,病灶在第一段(原生壳与引擎);首屏出现但卡住不能动,病灶在 JS 首帧任务(常见于首屏就发起了过多同步初始化)。把模糊的「启动慢」拆成可归因的段落,优化才有的放矢。

双端生命周期:同一张图的两套方言

应用进入后台、回到前台、被系统回收——这些状态切换在 iOS 与 Android 上各自有一套原生事件,RN 把它们统一映射成 AppState 的三种取值:active 表示前台可交互,background 表示已进入后台,inactive 是 iOS 特有的过渡态(来电、下拉通知中心的瞬间)。对照关系如下表:

应用状态 iOS 侧对应事件 Android 侧对应事件 AppState 取值
前台可交互 成为活跃应用 活动恢复可见 active
失去焦点但未后台 进入非活跃(仅 iOS) 活动暂停 active 或 inactive 过渡
进入后台 应用进入后台 活动停止 background
被系统回收 进程终止 进程被杀 无事件,需持久化兜底

注意最后一行:进程被杀时不会有任何事件通知你,这是双端一致的残酷规则——重要状态必须「随写随存」,不能指望退出回调(第 4 章持久化一节会展开这个纪律)。另外两端有一个经典行为差异:Android 的返回键可以在 JS 层拦截处理,iOS 没有对应的物理返回概念,手势返回由系统接管——这让「退出确认」类逻辑在两端需要不同的实现策略。

动手:随生命周期管理资源

监听前后台切换的标准写法如下,重点看订阅如何随组件卸载正确清理——这是第 6 章内存泄漏主题的第一次预演:

import React from 'react'; import { AppState, Text } from 'react-native'; export function SyncGate() { const [state, setState] = React.useState(AppState.currentState); React.useEffect(() => { // 订阅前后台切换事件 const sub = AppState.addEventListener('change', next => { setState(next); if (next === 'background') { // 进入后台:暂停轮询、刷新令牌、上报埋点等收尾动作 // 注意:Android 后台存活时间有限,收尾要快,别赌来得及 } }); // 组件卸载时移除订阅,否则监听器会一直挂在 AppState 上 return () => sub.remove(); }, []); return <Text>当前状态:{state}</Text>; }

工程上还有一条容易被忽略的纪律:进入后台时的「收尾动作」要按优先级裁剪。iOS 给后台任务的宽限时间以秒计,Android 在新版系统上对后台执行限制更紧,把耗时的收尾(比如全量数据同步)放到前台恢复时做,后台只做轻量的(比如暂停动画、写一个时间戳),是双端都适用的保守策略。

温启动与冷启动:别测错了对象

测量启动前还要分清两种启动。冷启动:进程全新创建,从操作系统拉起进程开始走完整三段——这是用户「点开应用」的真实体验,也是优化的主战场。温启动:进程还在(后台未被杀),只是把界面拉回前台,基本只走生命周期的前台切换,速度快一个量级。两者混淆会让测量数据完全失真:测试机上反复点开「退出到桌面再点开」,多数时候是温启动——进程大概率还活着;真正的冷启动要用工具主动结束进程后再启动。发布后线上监控区分两者的标志是「进程创建时间戳」,开发期最简单的办法是每次测量前用命令行强制停止应用。

温启动也不是不用管:从后台回到前台时的恢复速度(恢复渲染、重连数据流)同样在用户的体感账本上,尤其是切出去回个消息再切回来的高频动作。优化重点不同——冷启动的敌人是初始化量,温启动的敌人是前台的恢复工作量(重建了多少视图、刷新了多少数据)。测量口径分开立账,优化才不会张冠李戴。

完整案例:启动耗时测量与归因

背景:某资讯类应用反馈安卓端冷启动明显慢于 iOS,产品要求给出数据与方案。操作:先在两端各装性能记录方案——原生侧记录壳就绪时间戳,JS 侧在入口首行与首屏挂载完成处各打一个时间戳,三段口径的起止点由此对齐;然后采集五十次冷启动样本(冷启动指进程全新创建,注意排除温启动干扰)。结果:数据显示 Android 端的「引擎与包装载」段明显更长,其中包体积与启动时的同步模块初始化是大头;iOS 端三段分布均匀。解读:Android 慢不是玄学,包装载段的耗时与 JS 包体积正相关,而该项目历史上往包里塞了大量低频使用的初始化代码。变式与后续:短期把低频初始化改为延迟触发(首帧后再做),中期按第 8 章的构建方案拆分与瘦身包体——注意这条结论在新架构下依然成立,TurboModules 治的是「原生模块」的按需化,JS 侧的初始化纪律仍要自己遵守。这个案例也再次演示了本节的核心方法论:拆段、打点、归因,让每一段耗时都有人认领。

本节要点回顾

  • 启动三段口径:原生壳就绪、引擎与包装载、首屏可交互,拆段才能归因;
  • Hermes 的贡献点在装载段:预编译字节码免解析,是新版本启动提速的主因;
  • AppState 是双端方言的普通话:active、background 加 iOS 特有 inactive,映射表要记牢;
  • 进程被杀无事件:重要状态随写随存,别把数据安全寄托在退出回调上;
  • 后台收尾要轻:宽限时间以秒计,重活留到回前台再做。

至此引擎盖下的世界已经巡完。下一章回到方向盘前:组件、样式与交互,那些你每天真正在写的代码。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U