可以把 React Native(RN)启动流程理解成一条链:
arduino
App 启动
↓
Native 启动 RN
↓
创建 ReactInstance / Runtime
↓
加载 JS Bundle
↓
初始化 Bridge / JSI
↓
执行 JS
↓
React 创建 Fiber Tree
↓
Shadow Tree / Layout
↓
提交 UI 更新
↓
Native 创建原生 View
↓
首屏显示
1. Bundle 加载
以 Android 为例,Native 启动 RN 后,会创建 ReactInstanceManager,随后准备 JS 执行环境。
Bundle 可能来自:
bash
开发环境:
Metro Server
↓
http://localhost:8081/index.bundle
生产环境:
assets/index.android.bundle
加载完成后,JS Bundle 本质上就是一份可以被 JS Runtime 执行的 JavaScript 代码。
例如:
javascript
AppRegistry.registerComponent(
'MyApp',
() => App
);
此时只是代码加载进来了,还没有真正把 React UI 渲染出来。
2. Bridge 初始化
这是传统 RN 架构里非常核心的一步。
大致可以理解为:
arduino
┌───────────────┐
│ JavaScript │
│ Runtime │
└───────┬───────┘
│
Bridge
│
┌───────▼───────┐
│ Native │
│ Android/iOS │
└───────────────┘
JS 和 Native 两边分别有自己的执行环境。
例如 JS:
scss
NativeModules.UserModule.getUser()
最终需要把调用传递给 Native。
传统 Bridge 的核心特征是:
arduino
JS
↓
序列化
↓
Bridge
↓
Native
↓
执行
↓
返回数据
↓
Bridge
↓
JS
所以 Bridge 本质上承担:
JS ↔ Native 的通信通道
3. JS Runtime 启动
Bundle 加载之后,需要由 JS Runtime 执行。
RN 历史上主要使用:
JavaScriptCore
后来 RN 逐渐推广:
Hermes
因此:
Bundle
↓
Hermes / JSC
↓
执行 JavaScript
然后 JS 世界开始执行 RN 的初始化代码。
4. React Root 创建
接下来会执行:
scss
AppRegistry.registerComponent(...)
然后 Native 侧启动对应的 React Root。
最终进入:
scss
React
↓
App
↓
View
↓
Text
↓
...
例如:
javascript
function App() {
return (
<View>
<Text>Hello RN</Text>
</View>
);
}
React 会根据组件结构建立自己的:
php
Fiber Tree
可以简单理解成:
markdown
App
│
└── View
│
└── Text
5. Shadow Tree / Layout
React 计算出 UI 更新之后,还需要确定:
arduino
x
y
width
height
RN 使用 Yoga 做布局计算。
例如:
less
<View
style={{
width: 100,
height: 50,
margin: 10
}}
/>
最终需要计算:
ini
x = 10
y = 10
width = 100
height = 50
于是流程进一步变成:
markdown
React Tree
↓
Shadow Tree
↓
Yoga Layout
↓
计算布局
6. UI Commit
布局完成后,RN 会把需要发生的 UI 变化提交给 Native。
传统架构可以粗略理解为:
arduino
JS
↓
生成 UI 描述
↓
Bridge
↓
Native
↓
UIManager
↓
创建 View
例如:
xml
<View>
<Text>Hello</Text>
</View>
Native 最终可能创建:
Android
ViewGroup
└── TextView
iOS 则对应:
objectivec
UIView
└── UILabel
7. 首屏渲染
最终 Native UI Tree 创建完成:
sql
React Component
↓
Fiber Tree
↓
Shadow Tree
↓
Yoga Layout
↓
Commit
↓
Native View
↓
GPU / Render
↓
📱 首屏显示
所以真正的首屏可见并不是 Bundle 加载完成时,而是在:
JS 执行 → React 计算 → Layout → Commit → Native View 创建 → 系统绘制
之后。
一张完整时序图
sql
Native JS
│ │
│ 启动 RN │
├───────────────────────────►│
│ │
│ 创建 JS Runtime │
│───────────────────────────►│
│ │
│ 加载 Bundle │
│───────────────────────────►│
│ │
│ 执行 JS
│ │
│ AppRegistry
│ │
│ React Root
│ │
│ Fiber Tree
│ │
│ Shadow Tree
│ │
│ Yoga Layout
│ │
│◄──── UI Commit ────────────│
│ │
│ 创建 Native View │
│ │
│ Layout / Measure │
│ │
│ Draw │
│ │
│ 📱 首屏 │
但要注意:新架构已经不是简单的"Bridge"
如果你是在准备 RN 原理 / 面试 / 性能优化,这里非常重要。
现代 RN New Architecture 主要涉及:
arduino
旧架构
JS
│
│ Bridge
│
▼
Native
而新架构更接近:
markdown
JS
│
▼
JSI
│
├── TurboModules
│
└── Fabric
│
▼
Native UI
也就是:
markdown
React
│
Fiber Tree
│
React Renderer
│
Fabric
│
Shadow Tree
│
Commit/Layout
│
Native UI Tree
同时 Native Module 侧:
JS
│
▼
JSI
│
▼
TurboModule
│
▼
Native
因此现在如果问:
"RN 启动流程:Bundle 加载 → Bridge 初始化 → 首屏渲染"
更准确的回答应该区分:
Legacy Architecture:
arduino
Bundle
↓
JS Runtime
↓
Bridge
↓
React
↓
Shadow Tree
↓
Yoga
↓
UIManager
↓
Native View
↓
首屏
New Architecture:
sql
Bundle
↓
JS Runtime
↓
JSI
↓
React
↓
Fabric / Shadow Tree
↓
Yoga
↓
Commit
↓
Native View
↓
首屏
其中一个很关键的面试点是: "Bridge 初始化"不是新架构下最准确的表述,JSI/Fabric/TurboModules 才是理解新架构启动与通信的关键。
我也可以给你画一张 "RN 启动全链路 + Legacy/New Architecture 对比图" 。