当你第一次用React Native写完一个按钮,点击后看到原生界面乖乖响应时,可能会惊叹:"JavaScript居然能指挥原生控件?"这种魔法般的体验,让无数开发者爱上RN。但当你 profiling 应用时发现莫名其妙的白屏,或列表滚动掉帧时,又会困惑:"我的JS代码到底在哪执行?它和原生UI之间隔着什么?"这些问题的答案,都藏在RN运行时的三线程通信、Bridge序列化与JSI直接调用的细节里。本文将抛开JSX与样式表,带你深入C++层,看清每一帧渲染如何跨越语言边界,以及新架构如何让"JS写原生"真正飞起来。
一、核心架构概览
React Native 运行在三个主要线程 上:

二、旧架构:Bridge 机制(Legacy Architecture)
先讲一下旧架构,即Bridge机制
1. 工作原理
Bridge 是 React Native 0.68 之前 的核心,采用异步序列化通信 :

那何为异步序列化呢,以下有几个概念:
-
异步性:所有调用都是异步的,无法同步返回复杂数据
-
序列化开销:大数据量通信时性能瓶颈明显
-
单通道:所有通信挤在一个队列,容易阻塞
三、新架构:JSI + Fabric + TurboModules
1. JSI (JavaScript Interface)
JSI 是 C++ 层,提供了直接持有原生对象引用的能力 :
javascript
// C++ 侧暴露原生对象
class NativeModule {
public:
void showToast(jsi::String message) {
// 直接调用原生 API
}
};
// JS 侧直接同步调用
const nativeModule = global.__turboModuleProxy('ToastAndroid');
nativeModule.showToast('Hello'); // 同步执行!
核心优势:
-
同步调用:支持同步返回复杂对象
-
对象引用:JS 直接持有 C++ 对象指针,无需序列化
-
动态绑定:运行时动态加载模块,启动更快
2. Fabric 渲染系统
Fabric 是新的 UI 渲染器,取代旧的 UI Manager :
单说概念比较抽象,举两个例子:
旧渲染模型 :JS线程算完布局 → 写信 序列化 成 JSON → 寄到 Shadow 线程排好版 → 再寄到 UI 线程画出来。全程异步单通道,一步堵步步堵。
新渲染模型 :JS 通过 JSI 直接给 C++ 层打电话 → C++ 一边算布局一边指挥 UI 线程画。同步调用,两边同时干活,不绕弯子。
流程对比图
总感觉我举得栗子还是比较抽象,让AI帮我们想一个例子
旧架构(像邮寄信件)
scss
JS线程:画好图纸 → ✉️ 打包邮寄 → Shadow线程:量尺寸排版 → ✉️ 再寄 → UI线程:施工盖楼
(序列化) 等3-5帧 (Yoga) 等3-5帧 (60ms+)
新架构(像视频通话+无人机指挥)
scss
JS线程:图纸直接投屏到 C++ 层 → C++:实时算尺寸并指挥 → UI线程:同步施工
(JSI对象引用) (共享内存) (20ms内)
核心区别:老架构把数据当"包裹"传来传去,新架构让 JS 直接"捏"着原生对象的遥控器,省掉中间商赚差价。
Fabric 的关键改进:
-
C++ 层统一布局:Yoga 在 C++ 运行,跨平台一致性更好
-
异步优先级渲染:支持 React 18 的并发特性
-
更短的渲染路径:减少线程切换
3. TurboModules
TurboModules 是懒加载的原生模块系统:
旧架构 Native Modules有个很大的槽点,就是启动就全加载 :不管用不用,所有原生模块(相机、定位、蓝牙等)在 App 启动时一次性初始化,像开机自启 50 个软件,启动慢。
而新架构有了TurboModules,支持懒加载,大大降低启动时间,降低内存占用
dart
// 自动生成的 C++ 接口
struct ToastAndroidSpec : TurboModule {
void show(String message, int duration);
};
// JS 侧按需加载,首次调用时才初始化
const Toast = TurboModuleRegistry.get('ToastAndroid');
Toast.show('Lazy loaded!'); // 启动时不加载,减少启动时间
四、启动流程详解
1. 应用启动阶段
应用启动阶段是个线性的过程,比较好理解:

关键时间点:
- Before JS:原生代码加载,约 50-200ms
- JS Load:加载 bundle,影响最大(可拆包优化)
- JS Exec:执行 JS 代码,初始化模块
- First Paint:首帧渲染
2. Hermes 引擎的优化
Hermes 是 Facebook 为 RN 定制的 JS 引擎,要比之前启动速度提升30%以上,因为Hermes将字节码做了预编译:
传统:JS 源码 ➔ 解析 ➔ 编译 ➔ 执行
而Hermes:JS ➔ 预编译为 HBC 字节码 ➔ 直接执行
五、所以,为什么RN快?
| 优化方向 | 具体措施 | 原理 |
|---|---|---|
| 启动速度 | 启用 Hermes、使用 Codegen、减少 bundle 体积 | 减少 JS 执行和解析时间 |
| 通信效率 | 迁移到 TurboModules、减少 Bridge 调用 | 同步调用,避免序列化 |
| 渲染性能 | 使用 Fabric、合理使用 Memo/VirtualizedList | 减少线程切换和重绘 |
| 内存占用 | 及时销毁监听器、避免在 state 存大数据 | 防止内存泄漏 |
六、总结对比
| 特性 | 旧架构 (Bridge) | 新架构 (JSI+Fabric) |
|---|---|---|
| 通信方式 | 异步 JSON 序列化 | 同步直接调用 |
| 线程模型 | 多线程切换频繁 | C++ 层统一处理 |
| 启动速度 | 较慢 | 提升 30-50% |
| 内存占用 | 较高 | 更低 |
| 推荐度 | ❌ 已废弃 | ✅ 必须使用 |
实际建议 :新项目强制启用新架构(newArchEnabled=true),旧项目逐步迁移。理解运行时原理是写出高性能 RN 代码的基础。