RN 0.63 旧架构下,Android 和 iOS 的冷启动都经历了相同的思路:主线程入口 → 后台线程做重活(创建引擎、加载 Bundle)→ JS Thread 接管 → Shadow 计算布局 → 主线程渲染首帧。两端实现细节不同,但线程模型一致。
一、涉及的线程
iOS(4 条线程/队列)
| 线程/队列 | 名称 | 负责什么 |
|---|---|---|
| 主线程 | Main Thread | AppDelegate 入口、RCTRootView 挂载、最终 UIKit 渲染 |
| 后台初始化队列 | Init(GCD background queue) | 创建 JS 引擎、JS Thread、注册模块、加载 Bundle |
| JS 线程 | JS Thread(NSThread + CFRunLoop) | 执行 Bundle,驱动后续 JS 逻辑 |
| 布局计算队列 | Shadow Queue(GCD serial queue) | Yoga 布局计算,生成 UIBlocks |
Android(5 条线程)
| 线程 | 名称 | 负责什么 |
|---|---|---|
| 主线程 | Main Thread | App 入口、Activity 创建、ReactContext 挂载、最终 UI 渲染 |
| 后台初始化线程 | Init Thread(AsyncTask) | 创建 JS 引擎、Bridge、注册模块、加载 Bundle |
| JS 线程 | JS Thread(MessageQueueThread) | Bundle 执行完后启动,负责所有后续 JS 逻辑 |
| 布局计算线程 | Shadow Thread | Yoga 计算布局,构建 Shadow Tree |
| UI 线程 | UI Thread | 将布局结果转成真实 Android View(实际就是主线程) |
二、iOS 冷启动流转
┌──────────────────────────────────────────────────────────┐
│ 1. App 冷启动(主线程) │
└──────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────┐
│ AppDelegate.application:didFinishLaunching │
│ 创建 RCTBridge(只是配置,未启动 JS) │
│ 创建 RCTRootView │
└───────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────┐
│ RCTRootView 触发 RCTBridge 开始初始化 │
│ → RCTBridge 内部创建 RCTCxxBridge │
└───────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切入后台队列(GCD background) ✦ ══════════════════
┌──────────────────────────────────────────────────────────┐
│ 2. RCTCxxBridge 初始化(后台 GCD queue) │
└──────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ a. 创建 JS 引擎(JSC 或 Hermes) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ b. 创建 JS Thread │
│ NSThread + CFRunLoop 驱动 │
│ 线程名:com.facebook.react.JavaScript │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ c. 注册 NativeModules │
│ 扫描所有 RCTBridgeModule,生成模块配置表 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ d. 加载 JS Bundle │
│ Dev:HTTP 读取 Metro │
│ Release:NSBundle mainBundle │
└─────────────────────────────────────────────┘
══════════════════ ✦ 切到 JS Thread ✦ ══════════════════
▼
┌──────────────────────────────────────────────────────────┐
│ 3. 执行 JS Bundle(JS Thread) │
│ - 定义所有模块 │
│ - 注册 ViewManagers │
│ - AppRegistry.registerComponent │
└──────────────────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切回主线程 ✦ ══════════════════
┌──────────────────────────────────────────────────────────┐
│ 4. RCTBridge 通知 RCTRootView bridge 就绪(主线程) │
│ → 调用 AppRegistry.runApplication │
│ → JS 开始描述 UI 结构 │
└──────────────────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切到 Shadow Queue ✦ ══════════════════
┌─────────────────────────────────────────────┐
│ 5. RCTShadowView 布局计算(Shadow Queue) │
│ - 构建 Shadow Tree │
│ - Yoga 计算布局 │
│ - 生成 UIBlocks 放入 _pendingUIBlocks │
└─────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切回主线程 ✦ ══════════════════
┌─────────────────────────────────────────────┐
│ 6. RCTUIManager flush UIBlocks(主线程) │
│ - 创建 / 更新真实 UIKit View │
│ - 由 CADisplayLink 每帧触发 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 7. RN UI 首帧渲染完成 │
└─────────────────────────────────────────────┘
三、Android 冷启动流转
┌──────────────────────────────────────────────────────────┐
│ 1. App 冷启动(主线程) │
└──────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────┐
│ Application.onCreate() │
│ 创建 ReactNativeHost(仅配置,不创建 RN 实例) │
└───────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────┐
│ Activity.onCreate() │
│ 创建 ReactRootView │
└───────────────────────────────────────────────┘
│
▼
┌───────────────────────────────────────────────┐
│ ReactRootView.startReactApplication() │
│ → 获取 ReactInstanceManager(RIM) │
│ → RIM.createReactContextInBackground() │
└───────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切入后台线程(Init Thread) ✦ ══════════════════
┌──────────────────────────────────────────────────────────┐
│ 2. ReactContextInitAsyncTask.run()(后台线程) │
└──────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ a. 创建 JS 引擎(JSC 或 Hermes) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ b. 创建 CatalystInstance(C++ Bridge) │
│ JS ↔ C++ ↔ JNI ↔ Java 四层通信 │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ c. 注册 NativeModules(由 ReactPackage 提供) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ d. 加载 JS Bundle │
│ Dev:HTTP 读取 Metro │
│ Release:assets://main.jsbundle │
└─────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ e. 执行 JS Bundle │
│ - 定义所有模块 │
│ - 注册 UIManager / ViewManagers │
│ - AppRegistry.registerComponent │
│ → JS Thread 启动(MessageQueueThread) │
└──────────────────────────────────────────────────────────┘
══════════════════ ✦ 切回主线程 ✦ ══════════════════
▼
┌──────────────────────────────────────────────────────────┐
│ 3. RIM.setupReactContext()(主线程) │
│ - 创建 ReactContext │
│ - 通知所有 ReactRootView attach │
│ - 触发 UIManager.createRoot │
└──────────────────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切到 Shadow Thread ✦ ══════════════════
┌─────────────────────────────────────────────┐
│ 4. Yoga 布局计算(Shadow Thread) │
│ - 构建 Shadow Tree │
│ - 计算各节点尺寸和位置 │
└─────────────────────────────────────────────┘
│
▼
══════════════════ ✦ 切到 UI Thread(主线程) ✦ ══════════════════
┌─────────────────────────────────────────────┐
│ 5. UIManager 操作 Android View │
│ createView / updateView / manageChildren │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ 6. RN UI 首帧渲染完成 │
└─────────────────────────────────────────────┘
四、双端对比
| 环节 | Android | iOS |
|---|---|---|
| 应用入口 | Application.onCreate() + Activity.onCreate() |
AppDelegate.application:didFinishLaunching |
| RN 根视图 | ReactRootView |
RCTRootView |
| Bridge 管理器 | ReactInstanceManager(RIM) |
RCTBridge |
| Bridge 实体 | CatalystInstance(Java + JNI + C++) |
RCTCxxBridge(ObjC + C++,无 JNI) |
| 后台初始化方式 | AsyncTask |
后台 GCD queue |
| JS Thread 驱动 | MessageQueueThread(Looper/Handler) |
NSThread + CFRunLoop |
| NativeModule 注册 | ReactPackage |
RCTBridgeModule 宏 |
| Shadow 计算 | Shadow Thread(独立 Java 线程) | Shadow Queue(GCD serial queue) |
| UI 更新 | UIManager → Android View |
RCTUIManager → UIKit View |
| UI 帧驱动 | Choreographer | CADisplayLink |
| 通信层 | JS ↔ C++ ↔ JNI ↔ Java(4层) | JS ↔ C++ ↔ ObjC(3层,无 JNI) |
iOS 比 Android 少一层 JNI,因为 ObjC 支持直接混编 C++(.mm 文件),不需要额外的跨语言桥接。
五、名词解释
ReactNativeHost
Android 侧 RN 的全局配置容器,工厂模式。只持有配置(Bundle 路径、Dev 模式开关等),不直接创建 RN 实例,由 ReactInstanceManager 负责真正的初始化。
ReactRootView / RCTRootView
RN 的根视图容器。Android 侧继承自 FrameLayout,iOS 侧继承自 UIView。作用一样:作为 Native 布局和 RN 渲染内容的边界,RN 渲染的所有组件都挂在它下面。
ReactInstanceManager(RIM)
Android 侧 RN 实例的调度中心。负责创建 JS 引擎、管理 ReactContext 生命周期、协调各线程的初始化顺序。iOS 侧对应的是 RCTBridge。
ReactContextInitAsyncTask
Android 的 AsyncTask 子类,专门把 RN 初始化的耗时工作(创建引擎、加载 Bundle)移到后台线程,避免主线程被阻塞。
CatalystInstance
旧架构 Android 侧的 Bridge 核心实体,负责 JS ↔ C++ ↔ JNI ↔ Java 四层通信。所有 JS 调 Native、Native 调 JS 都经过它,且必须 JSON 序列化。新架构用 JSI 替掉了它。
JNI(Java Native Interface)
Java 调用 C/C++ 原生代码的桥接机制。因为 JS 引擎(JSC/Hermes)是 C++ 写的,Android 业务层是 Java,两者必须通过 JNI 跨语言调用。iOS 没有这层,ObjC 可以直接混编 C++。
ReactPackage
Android 侧注册 NativeModule 的方式。开发者实现 ReactPackage 接口并返回模块列表,RN 初始化时统一扫描注册。iOS 侧用 RCTBridgeModule 宏替代,自动注册,不需要手动列举。
JS Bundle
Metro 打包后的 JavaScript 产物(main.jsbundle)。包含所有业务代码和第三方库。Dev 模式从 Metro HTTP 服务实时拉取,Release 模式预先打包进 App 资源目录。
MessageQueueThread
Android 侧 JS Thread 的实现,基于 Looper + Handler 机制。是一个有消息队列的后台线程,所有 JS 任务串行投递到这里执行。iOS 侧对应的是 NSThread + CFRunLoop。
ReactContext
RN 的运行时容器,持有 JS 执行环境、NativeModule 注册表、Bridge 实例等。可以理解为 RN 的"全局上下文",初始化完成后通知所有 ReactRootView 开始渲染。
UIManager / RCTUIManager
负责将 JS 描述的 UI 结构转换为真实 Native View 的管理器。接收来自 JS 的 createView、updateView、manageChildren 等指令,在主线程操作真实 View。
Shadow Tree / ShadowNode / RCTShadowView
RN 的虚拟布局树。每个 JS 组件对应一个 Shadow 节点,存储布局属性(宽高、padding、flex 等)。布局计算在 Shadow Thread / Shadow Queue 中进行,不占用主线程。
Yoga
Facebook 开源的跨平台布局引擎,实现了 CSS Flexbox 规范,Android 和 iOS 共用同一套 C++ 实现。RN 在 Shadow Thread 中用 Yoga 计算每个节点的实际尺寸和位置。
RCTBridge / RCTCxxBridge
iOS 侧的 Bridge 管理器(RCTBridge)及其 C++ 实现层(RCTCxxBridge)。RCTBridge 是对外的 ObjC 接口,RCTCxxBridge 是真正执行初始化的 C++ 核心,负责创建 JS 引擎、JS 线程、注册模块。
RCTBridgeModule
iOS NativeModule 的注册协议。在 ObjC 类里加上 RCT_EXPORT_MODULE() 宏,RN 初始化时自动扫描注册,不需要像 Android 那样在 ReactPackage 里手动列举。
_pendingUIBlocks
RCTUIManager 内部的待执行 UI 操作队列。Shadow Queue 计算完布局后,把需要做的 View 操作封装成 Block 放进来,等 CADisplayLink 触发时批量提交到主线程执行,避免频繁切换主线程。
CADisplayLink / Choreographer
屏幕刷新率同步计时器。iOS 用 CADisplayLink,Android 用 Choreographer,都是每帧(~16.7ms)触发一次,驱动 RN 把 _pendingUIBlocks 批量提交到主线程更新 UI。
六、与新架构的对比
旧架构(0.63)的瓶颈主要集中在 Init Thread 这一段:
| 旧架构 | 新架构改进 |
|---|---|
CatalystInstance:四层序列化通信 |
JSI:JS 直接持有 C++ 对象引用,无序列化 |
| NativeModules 启动时全量注册 | TurboModules:懒加载,首次调用时才初始化 |
| Shadow Tree 可变,需要线程锁 | Fabric:Shadow Tree 不可变,多线程安全 |
| 不支持 React 并发特性 | Fabric 支持可中断渲染、优先级调度 |