React Native 运行时深度解析

当你第一次用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 代码的基础。

相关推荐
牛奶1 小时前
2026年大模型怎么选?前端人实用对比
前端·人工智能·ai编程
牛奶1 小时前
前端人为什么要学AI?
前端·人工智能·ai编程
Kagol4 小时前
🎉OpenTiny NEXT-SDK 重磅发布:四步把你的前端应用变成智能应用!
前端·开源·agent
GIS之路5 小时前
ArcGIS Pro 中的 notebook 初识
前端
JavaGuide5 小时前
7 道 RAG 基础概念知识点/面试题总结
前端·后端
ssshooter5 小时前
看完就懂 useSyncExternalStore
前端·javascript·react.js
格砸6 小时前
从入门到辞职|从ChatGPT到OpenClaw,跟上智能时代的进化
前端·人工智能·后端
Live000007 小时前
在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
前端·javascript·react native
柳杉7 小时前
使用Ai从零开发智慧水利态势感知大屏(开源)
前端·javascript·数据可视化