Skip to content
雲里
里雾

React Native 新架构概览

mindgym 开发 更新于 2026/4/12

React Native 新架构(JSI + Fabric + TurboModules + Hermes)是对 2015 年旧架构根本性的重写,核心驱动力是:用直接内存访问替代 JSON 序列化的异步消息队列,从根本上消灭旧 Bridge 带来的性能天花板。本页从旧架构的具体痛点出发,逐层拆解新架构每个组件的设计动机。


概述:旧架构到底有什么问题?

要理解新架构,必须先理解旧架构——不是因为旧架构”不好”,而是它在 2015 年是一个合理的工程决策,但在 2020 年代已经撑不住了。

旧架构的三线程模型

旧架构把整个 RN 运行时拆成三条线程,彼此通过一个叫 Bridge 的消息总线通信:

┌─────────────────┐    JSON 消息队列    ┌─────────────────┐
│   JS Thread     │ ──────────────────► │   UI Thread     │
│                 │                     │  (主线程)        │
│  React 渲染树   │ ◄────────────────── │  原生视图操作    │
│  业务逻辑       │    JSON 消息队列    │  用户输入事件    │
└─────────────────┘                     └─────────────────┘
         │                                       │
         │           JSON 消息队列               │
         ▼                                       ▼
┌─────────────────────────────────────────────────────────┐
│                   Shadow Thread                          │
│           (也叫 Layout Thread / Yoga Thread)             │
│    负责运行 Yoga 布局引擎,把 React 的 flexbox 计算      │
│    转成原生视图的具体坐标和尺寸                          │
└─────────────────────────────────────────────────────────┘

三条线程各司其职:

这个设计的好处是:JS 不阻塞 UI,JS 崩了主线程还在。问题是,三条线程沟通必须经过 Bridge——而 Bridge 有三个硬伤。

Bridge 的三个具体痛点

痛点 1:JSON 序列化开销

Bridge 本质上是一个异步消息队列。JS 侧要调用一个 Native 方法时,不能直接调用,必须:

  1. 把参数序列化成 JSON 字符串
  2. 把 JSON 字符串放进队列
  3. Native 侧从队列取出
  4. JSON 反序列化成 Native 数据结构

对于「每帧 60 次的滚动事件」、「动画的每一帧位置更新」,每秒 60 次 × 序列化/反序列化,开销积累非常可观。

痛点 2:异步延迟带来的动画掉帧

旧架构里,JS Thread 控制动画逻辑,每一帧都要通过 Bridge 把新的位置值发给 UI Thread。Bridge 是异步的——当 JS Thread 被任何业务逻辑占用(比如处理一个大列表的 state 更新),动画帧就会饿死,直接掉帧。这也是为什么早期 RN 项目「用 JS 写动画很难丝滑」。

痛点 3:单通道、无类型的消息队列

所有 JS 和 Native 的通信共用同一条 Bridge。不管是事件处理、布局计算、还是 Native 模块调用,全部挤在一条队列里。任何一个调用量大的地方都可能让整条通道堵塞。更糟的是,消息格式是 JSON,没有类型信息。改参数名会在运行时静默失败,没有编译期保障。


历史背景:架构演进时间线

年份事件
2015React Native 开源,Bridge 架构随之诞生。当时主要目标是「让 JS 可以驱动原生 UI」,Bridge 是最直接的实现方式。
2018Meta 内部开始 JSI(JavaScript Interface)RFC。核心动机:能不能让 JS 直接持有 Native 对象的引用,跳过 JSON 序列化?
2019Hermes 引擎开源。Meta 内部数据显示 App 启动时间中有大量时间花在 V8/JSC 的 JIT 预热上,Hermes 用字节码预编译解决这个问题。
2021新架构进入 beta,JSI / Fabric / TurboModules 同步推进。Fabric 重写渲染器,TurboModules 重写 Native 模块系统。
2022RN 0.68 起允许「opt-in」启用新架构,但默认关闭。生态库还不完全兼容。
2024RN 0.76 新架构默认开启。Meta 在内部 App(Facebook、Instagram)验证了足够的稳定性。Expo SDK 52+ 跟进。
2025Expo SDK 54(MindGym 使用的版本),RN 0.81/0.82,新架构是默认状态,旧架构支持进入 deprecation 轨道。

工作方式

JSI:跳过 Bridge 的关键

JSI 全名 JavaScript Interface,是新架构最核心的基础设施。

旧架构的 Bridge 为什么必须用 JSON?因为 JS 引擎(V8 / JavaScriptCore)和 Native 代码(C++ / ObjC / Java)运行在完全不同的内存空间里。JS 的对象活在 JS 堆里,Native 无法直接访问,反之亦然。Bridge 用 JSON 做「中间格式」,本质上是把两个内存世界之间的传输问题转成了字符串序列化问题。

JSI 的解法:Host Object

JSI 引入了一个概念叫 Host Object——一个活在 C++ 里、但可以被 JS 直接引用的对象:

JS 侧:
  const mmkv = global.__mmkvInstance  // 这不是普通的 JS 对象
  mmkv.set('key', 'value')            // 这个调用直接触发 C++ 代码,同步返回

C++ 侧:
  // MMKV 注册了一个 Host Object,实现了 get/set 方法
  // JS 调用 mmkv.set() 时,JS 引擎通过 JSI 直接调用 C++ 的实现

关键词:同步无序列化直接内存访问

JSI 让 JS 可以持有 Native 对象的引用(不是副本),调用时不经过任何队列,返回值立即可用。这从根本上消灭了 Bridge 的三个痛点。

这也是为什么 MindGym 技术栈里选了 react-native-mmkv:MMKV 完全基于 JSI 实现,mmkv.getString('key') 是同步调用,不需要 await,读写性能比基于旧 Bridge 的 AsyncStorage 快约 30 倍。

Hermes:为 RN 定制的 JS 引擎

RN 旧架构用的是 JavaScriptCore(iOS 自带)或 V8(Android 可选)。这两个引擎是为浏览器设计的——它们假设你的代码会长时间运行,值得花时间做 JIT 编译优化。

移动 App 的场景完全不同:用户点开 App,3 秒内如果白屏就会关掉。JIT 预热需要时间,而这段时间恰好在 App 启动阶段——用户最敏感的时刻。

Hermes 的解法:字节码预编译

Hermes 在构建期(eas build 的时候)把你的 JS 代码编译成 Hermes 字节码(.hbc 文件),打进 App bundle 里。App 启动时,引擎直接执行字节码,跳过解析和编译阶段。

旧流程: App 启动 → 读取 JS 源码 → 词法分析/语法分析 → AST → 字节码 → 执行
新流程: App 启动 → 读取已编译的字节码 → 直接执行

Meta 的数据(2019 年 Hermes 发布博文):启用 Hermes 后,Android 的 TTI(Time to Interactive)从 4.3 秒降到 2.0 秒,内存占用下降约 40%,APK 体积下降约 6%。

Hermes 从 Expo SDK 48 / RN 0.71 起成为 iOS 和 Android 的默认引擎。

Fabric:重写渲染器

旧架构的渲染器叫 Paper,Shadow Thread 里跑着用 JS 实现的 Yoga 布局引擎,通过 Bridge 和 UI Thread 通信。

Fabric 的变化

Fabric 把整个渲染管线从 JS 移到了 C++:

直观类比:Paper 像是两座城市之间用电报通信,Fabric 是两座城市合并成一座城,本地通话。

TurboModules:懒加载 + 类型安全的 Native 模块

旧架构的 Native Modules 系统有一个问题:所有模块在 App 启动时全部初始化,哪怕你只用了其中 5 个。想象一下,你 import 了一个照相机模块,即使用户没有点击拍照,App 启动时相机相关的所有 Native 代码就已经加载并初始化了。

TurboModules 的改进

// 假设你在定义一个自定义 TurboModule(MindGym 目前不需要,但这是原理)
// 你在 TS 侧声明:
interface Spec extends TurboModule {
  getRandomSeed(): number;  // 同步
  saveRecord(data: SessionRecord): Promise<void>;  // 异步
}

// Codegen 会根据这份声明生成 iOS/Android 的接口文件
// Native 侧实现这些接口,类型由编译器保证

Bridgeless:终点站

Bridgeless 是新架构的最终状态:完全移除 Bridge 相关代码

在「新架构 + 仍有 Bridge」的过渡期(RN 0.68-0.75),Bridge 代码还保留着,旧的 Native Modules(不支持 TurboModules 的库)还能靠 Bridge 跑。Bridgeless 模式下,所有通信必须走 JSI / Fabric / TurboModules,Bridge 代码从 App bundle 里彻底删除。

global.RN$Bridgeless 是 RN 注入到 JS 全局对象的一个 boolean,当且仅当 App 运行在真正的 Bridgeless 模式下时为 true

// 在任意 React 组件或 .ts 文件里
if (global.RN$Bridgeless === true) {
  console.log('真正的 Bridgeless 模式,Bridge 已移除')
} else {
  console.log('Bridge 仍然存在(过渡期或旧架构)')
}

旧架构 vs 新架构对比

维度旧架构(Bridge / Paper)新架构(JSI / Fabric / TurboModules)
JS↔Native 通信异步 JSON 消息队列JSI 同步直接调用
序列化开销每次通信都要 JSON 序列化/反序列化无序列化,直接内存引用
Native Modules 加载App 启动时全部初始化懒加载,用到时才初始化
类型安全无(约定驱动,运行时才知道错)Codegen 从 TS 生成接口,编译期保障
渲染器Paper(JS + C++ 混合,Bridge 通信)Fabric(全量 C++,同步布局)
布局测量异步(发消息等回调)同步(C++ 直接返回)
Concurrent Rendering不支持支持(React 18 并发特性可用)
JS 引擎JSC / V8(JIT 为主)Hermes(字节码预编译,低启动延迟)

代码示例:MindGym 里我们在哪里验证新架构

1. app.json 启用新架构

// /Users/hat_cloud/Projects/MindGym/MindGymApp/app.json
{
  "expo": {
    "newArchEnabled": true,  // 这一行告诉 Expo 构建系统启用新架构
    ...
  }
}

newArchEnabled: true 在 Expo SDK 54 里做了两件事:

2. 运行时检测 global.RN$Bridgeless

// 例如放在 app/_layout.tsx 或任意启动早的位置
// 仅用于开发期调试,生产环境不需要这行
if (__DEV__) {
  console.log(
    '新架构状态:',
    global.RN$Bridgeless === true ? 'Bridgeless ✓' : '仍有 Bridge'
  )
}

在 Expo SDK 54 + 新架构默认开启的环境下,这行日志应该打出 Bridgeless ✓

3. MMKV 是 JSI 的活教材

import { MMKV } from 'react-native-mmkv'
const storage = new MMKV()

// 同步读写,不需要 await
storage.set('streak', 5)
const streak = storage.getNumber('streak')  // 立即返回,不是 Promise

如果用旧架构的 AsyncStorage,同样的操作需要:

await AsyncStorage.setItem('streak', JSON.stringify(5))
const raw = await AsyncStorage.getItem('streak')
const streak = raw ? JSON.parse(raw) : null

异步、需要序列化、需要错误处理——这是 Bridge 模型的直接后果。


面试视角

“说一下 RN 新架构”

抓手:旧架构 Bridge 的三个具体问题(序列化开销、异步延迟、无类型)→ 新架构用 JSI 替换 Bridge,用 Fabric 重写渲染器,用 TurboModules 重写 Native 模块系统,用 Hermes 替换 JS 引擎。不要背名词,要说清楚「每个组件解决了什么具体问题」。

“JSI 是什么?”

JSI 是让 JS 可以直接持有 C++ 对象引用的接口层。核心机制是 Host Object——一个活在 C++ 里但可以被 JS 直接操作的对象,调用时同步返回,无 JSON 序列化。和 Bridge 的本质区别在于:Bridge 是「两个进程用字符串通信」,JSI 是「同一个进程里 JS 直接调用 C++」。

“Fabric 和 Paper 的区别?”

Paper 是旧渲染器,Shadow Tree 用 JavaScript 维护,和 UI Thread 之间通过 Bridge 异步通信。Fabric 把 Shadow Tree 全量移到 C++,和 UI Thread 同步通信,消灭了布局测量的异步延迟。更重要的是,Fabric 支持 React 18 的 Concurrent Rendering,Paper 的架构在设计上就不支持。

“TurboModules 和 Native Modules 的区别?”

两个核心差异:① 懒加载,Native Modules 启动时全部初始化,TurboModules 按需加载;② 类型安全,Native Modules 靠约定,TurboModules 通过 Codegen 从 TS 生成接口,编译期保障类型正确。底层通信也从 Bridge 换成了 JSI。

“Bridgeless 是什么?”

Bridgeless 是新架构的最终形态——Bridge 代码从 App 里完全移除。在新架构过渡期(0.68-0.75),Bridge 还保留用于兼容老库。Bridgeless 完全切断这条退路,强制所有通信走 JSI。global.RN$Bridgeless === true 是运行时判断是否处于 Bridgeless 模式的方式,Reanimated、Expo 等库内部都在用这个标志。


版本说明

本页基于 MindGym M0 阶段(Expo SDK 54, RN 0.81.5, 2026-04-13)。

参见

参考