想象一个每天要处理上亿包裹的物流园区。老园区里,所有包裹先送到一个中央调度台,被人手记录、分类,再用小推车送到对应仓库;每到高峰期,调度台前堆满包裹,司机们只能排队等待。React Native 的旧版架构就像是这座调度台:JavaScript 与原生界面之间的一切沟通,都要经过一座异步的“桥”,消息需要序列化、排队、再回调,效率自然受限。 RN 新架构则是把整个园区升级成了一个智能物流园区:一条名为 JSI 的高速传送带让数据对象直接在 JS 与原生之间穿梭,Fabric 分拣机器人预先建好货架模型(影子树)后一次性入库,Hermes 引擎则像一台特制发动机,让整个园区更快启动、更省油耗。这篇文章就用这座园区改造的故事,带你理解 RN 新架构中 Fabric 渲染与 Hermes 引擎的底层原理。
学习这段知识,能帮你理解 React Native 重大升级中的底层设计取舍,在性能优化、架构迁移和新项目技术选型中做出有理有据的决策。
目录
可视化演示
展示React Native新架构中Fabric渲染器的UI树同步流程与Hermes引擎的字节码优化机制。切换模式查看渲染管线、引擎性能与架构对比。
本节配有交互动效(进入视口后自动加载,约 3KB)。
Fabric渲染管线 JS层生成React元素树,提交至Shadow Tree Fabric渲染器同步生成原生视图树 pipeline: JS → Shadow → Fabric → Native 同步渲染消除Bridge异步延迟
架构演进:从中央调度台到智能园区
老物流园区的中央调度台前,总有一群小推车来回跑。快递员把包裹(JS 要更新的 UI 指令)交给调度台,调度员记在本子上(序列化),再按顺序安排小推车(消息队列)送到各个仓库,等仓库反馈后,还得回程通知快递员(异步回调)。React Native 旧版架构就是这样:JS 与原生之间隔着一座异步 Bridge,每一次通信都要经历序列化、排队和回调。
新架构的目标不是“把桥修宽一点”,而是把整个园区重新设计。JSI 相当于在 JS 引擎和原生世界之间铺了一条高速传送带,对象引用可以直接共享;Fabric 相当于新的分拣机器人,先在后台搭好影子树再统一提交;Hermes 则是一台为园区定制的发动机。三者配合,从结构上消灭了“所有消息都在一座桥上排队”的瓶颈。
可以用一个简单的求和模型表达旧架构在 n 次通信上的总耗时:
老调度台的模式不是不能运转,而是每次扩建都只能增加更多小推车,治标不治本。新架构要做的,是把“中央调度台”整个换成“直连传送带 + 智能分拣”。
- n 次通信一次交互需要多次 JS 与原生之间的消息往来,n 表示消息总数。
- S_i 序列化耗时每次消息都要变成可传递的字符串,就像把包裹重新打包。
- Q_i 排队等待消息在桥接队列中等待前一个任务处理完。
- C_i 回调返回原生处理完结果后,还要异步回传一次。
JSI机制:园区里的高速传送带
在智能园区里,最重要的是一条高速传送带。旧模式里,包裹要想从 JS 仓库送到原生仓库,必须拆包、登记内容、装到小推车上,到了对面再重新组装;而新传送带可以直接让两个仓库共享同一个货架托盘,不需要反复拆包。这条传送带就是 JSI(JavaScript Interface)。
JSI 是一层轻量 C++ 接口,它让 JS 引擎与原生世界能够共享宿主对象引用。JS 可以直接拿到原生对象并调用其方法,方法返回值也能直接回到 JS 侧,整个过程不需要 JSON 序列化,也不需要异步回调解包。正因为有 JSI,Fabric、TurboModules 等新架构组件才能像不同仓库之间直连货架一样高效协作。
通信开销的改善可以用新旧对比表达:
传送带让园区里的仓库不再隔墙喊话,而是直接通过管道递货。JSI 正是这样的管道,它让“桥”这个词正式成为历史。
- m 条旧消息旧架构中一次复杂操作会产生若干条异步消息。
- S_i 与 Q_i每条消息仍要付出序列化和排队成本。
- T_sync 同步调用JSI 允许 JS 同步调用原生方法,只需极少时间。
Fabric渲染:提前搭好货架模型的分拣机器人
智能分拣机器人每次摆放货物前,不会直接乱放,而是先在电脑里建一套货架模型:哪个位置放什么、承重多少、取货顺序如何,确认无误后再指挥真实货架一次摆好。Fabric 渲染器就是这样工作的:在真正更新原生视图前,先在后台构建一棵“影子树”,用来描述界面结构、样式和布局,然后一次性提交给原生端。
影子树相当于 JS 侧界面状态的“施工图纸”。旧的异步桥接是“施工队边等图纸边干活”,图纸到的路径长,进度就慢;Fabric 则把布局计算放到后台线程,完成后再利用每一帧的空闲时间合批提交,避免 JS 线程被 UI 更新阻塞,也支持了 React 的并发渲染特性。
要保证动画不卡顿,单帧内的总耗时必须被牢牢控制:
分拣机器人不会让所有包裹都堆积在卸货口,而是按计划、按批次地移动,Fabric 让 UI 更新也有了自己的“调度表”,画面自然更顺滑。
- 1000 / f每帧可用的总时间预算,f 为目标帧率。
- T_shadow 影子树构建和 diff 影子树所花费的时间。
- T_layout 布局在后台线程计算布局所需的时间。
- T_commit 提交把产物合批提交给原生视图的时间。
Hermes引擎:提前提炼好燃料的特制发动机
园区里最省油的发动机,从不临时点火预热,而是使用一种在进园区前就提炼好的标准燃料块。Hermes 就是 React Native 专为移动端设计的 JS 引擎,它最大的特点是支持 AOT(预编译):在构建 App 时就把 JavaScript 预编译为字节码,设备端运行时只需要加载字节码并执行,省去了传统 JS 引擎“先解析源码、再做 JIT 编译”的过程。
这带来的直接好处就是启动更快、内存占用更低。对手机这类资源受限的终端来说,减少解析和编译动作,就像货车不需要在园区门口临时炼油,油耗和等待时间都大幅下降。Hermes 也做了针对移动端的内存回收优化,GC 暂停时间更短,不容易在滚动切换时出现明显卡顿。
启动收益可以写成:
发动机变得更高效,园区里的每一趟运输都因此受益。Hermes 是 RN 新架构体验中最容易被感知的那一环。
- T_bytecode加载和反序列化预编译字节码的时间。
- T_exec真正执行 JS 逻辑的时间,新旧引擎都需要。
- T_parse传统引擎解析 JS 源码的时间。
- T_compile传统引擎在运行时做 JIT 编译的时间。
TurboModules:只打开当前订单需要仓库门
智能园区把大仓库改成了很多小隔间,每个隔间按需开门:当前订单只碰几个隔间,而不会让所有隔间的门一整天全敞着,白白耗电。TurboModules 就是这样的原生模块体系,它让 JS 侧在真正需要某个原生能力时才加载对应模块,而不是 App 启动时就把所有原生模块全部初始化。
TurboModules 另一个关键点是“代码生成”:配合 Codegen,开发者用一份类型定义描述原生模块,构建时自动生成类型安全的 JS 与 C++/Java/OC 胶水代码。旧架构中运行时才知道的方法名、参数类型和错误,在编译期就能被发现,也不需要桥接层再做动态对象映射。
首屏加载收益可以这样衡量:
按需开门、类型保障、直连调用,让每一个原生模块都像园区里的智能隔间——用到才打开,打开即能用,不用不占资源。
- M_first 首屏模块体量App 首屏真正需要加载的原生模块大小。
- M_all 全部模块体量所有已注册原生模块的总大小。
性能优化:园区监控室的三个仪表盘
智能物流园区的总监控室会盯紧三个指标:首单送达时间、高峰期吞吐量、油耗。对应到 RN 新架构,就是可交互时间 TTI、渲染帧率和内存占用。优化的目标不是单点跑到最快,而是让“整条业务链”在真实设备上都稳定。
具体策略上:用 Fabric 的异步布局减少 JS 线程的阻塞;用影子树的增量 diff 减少无效 UI 更新;用 Hermes 降低启动解析耗时;用 TurboModules 减少首屏初始化;再配合性能监控工具观察长任务、掉帧和内存曲线,定位是渲染问题还是 JS 逻辑问题。这里可以用一个 TTI 模型串起各部分:
监控室的价值不是挂一堆仪表盘,而是看到哪段运输最耗油。性能优化也如此:先量化,再动手,让每次治理都有数据支撑。
- T_start 启动耗时从进程创建到 JS 引擎和框架初始化完成。
- T_first 首帧耗时从启动完成到第一帧渲染出来。
- L_k 长任务主线程上超过一定时长、会阻断用户响应的任务段。
迁移兼容:老仓库带着新传送带一起运转
老园区不会一夜之间把所有仓库全拆掉,而是先建新传送带,再通过“兼容连廊”让旧仓库继续发货,等旧仓库逐个改造完成后,再拆掉连廊。RN 新架构的迁移也是如此:通过新架构开关让 App 在原有代码基础上启用 Fabric 和 JSI,同时提供兼容层让旧桥接模块继续工作,再按模块逐步迁移到 TurboModules。
工程上通常采用灰度发布:先让一小部分用户开启新架构,观察崩溃率、帧率和内存后再扩大范围。迁移风险主要来自尚未替换的旧桥接模块——它们越多,新架构能发挥的直连红利就越少。
可以用一个风险估算模型来辅助决策:
迁移不是“一键重写”,而是有节奏的园区改造。兼容连廊帮我们守住稳定底线,新传送带则逐渐释放性能红利。
- α 影响系数旧模块平均业务影响权重,可能因模块复杂度而异。
- N_old 旧模块数仍通过兼容层运行的桥接模块数量。
- N_total 总模块数项目中全部原生模块数量。
AI 应用场景
CI 性能巡检机器人
阶段:构建质量门禁
解决的问题:传统方式依赖人工在真机测试,无法在每次发版前快速发现启动变慢、首帧掉帧等问题;AI 可以结合 Hermes 预编译产物和 Fabric 渲染日志,自动判断新架构是否在“变好”还是“退化”。
具体案例:某团队在 CI 流水线中集成一个脚本,每次构建后自动解析 Hermes 字节码加载耗时、首屏 TTI 和掉帧率,超过阈值就阻止合入。问题从“测试组发现”变成“构建阶段拦截”。
线上体验监控台
阶段:线上运行监控
解决的问题:新架构上线后,用户机型千差万别,单纯看均值无法定位哪棵影子树拖慢了渲染;AI 聚类分析可以按设备、页面、手势行为圈出高危场景,再结合 Fabric 的提交记录定位瓶颈。
具体案例:电商 App 开启新架构后,监控台发现某商品详情页在低端机上提交耗时偏高。通过影子树快照对比,定位到嵌套层级过深,优化后帧率提升 20%。
原生模块迁移助手
阶段:迁移辅助决策
解决的问题:老项目有几十个桥接模块,逐个迁移工作量大;AI 工具可以扫描模块调用频率、参数复杂度和影响范围,给出优先级排序,并自动生成 TurboModule 骨架代码。
具体案例:团队用脚本分析桥接模块调用热力图,将高频模块先在 codegen 下生成类型安全的 TurboModule,优先替换,三个月内把兼容层压力降了一半。
Python 演示
# -*- coding: utf-8 -*-import heapq class FrameTask: def __init__(self, tid, priority, cost): self.tid = tid self.priority = priority self.cost = cost class FabricSimulator: """模拟 Fabric 按优先级分帧提交的过程""" def __init__(self, budget_ms=16.0): self.budget = budget_ms self._queue = [] self._task_count = 0 self.committed_lists = [] def add_task(self, priority, cost): self._task_count += 1 heapq.heappush( self._queue, (-priority, self._task_count, FrameTask(self._task_count, priority, cost)) ) def tick_frame(self): used_ms = 0.0 finished = [] while self._queue and used_ms + self._queue[0][2].cost <= self.budget: _, _, task = heapq.heappop(self._queue) used_ms += task.cost finished.append(task) if finished: self.committed_lists.append(finished) return used_ms def run(self, frames): for i in range(frames): used_ms = self.tick_frame() status = "commit" if used_ms > 0 else "defer " print("Frame {:>2}: {:5.1f}ms used -> {}".format(i, used_ms, status)) print("Total committed frames:", len(self.committed_lists)) if __name__ == "__main__": sim = FabricSimulator() sim.add_task(3, 4.0) sim.add_task(1, 9.0) sim.add_task(2, 5.0) sim.add_task(4, 14.0) sim.add_task(2, 6.0) sim.run(4)
heapq.heappush(self._queue, (-priority, self._task_count, FrameTask(...)))用负优先级构造最小堆,确保高优先级任务先被弹出。while self._queue and used_ms + self._queue[0][2].cost <= self.budget:当前帧剩余预算足够时才执行任务,否则留给下一帧。self.committed_lists.append(finished)把这一帧内完成的任务合并成一批,对应 Fabric 的合批提交。status = "commit" if used_ms > 0 else "defer "如果这一帧没有任何任务完成,就说明上一帧预留了缓冲,避免 UI 掉帧。sim.run(4)连续运行 4 帧,观察调度器如何分配高优先级任务。
常见误区
误区我一直以为新架构就是把旧桥换成一条更宽、更快的高速公路,消息仍然是异步发送,只是速度变快了。
正解新架构不是桥的速度升级,而是拆掉了这座桥。JSI 让 JS 与原生共享对象引用,消息不再需要 JSON 序列化、排队和异步回调,而是像传送带直连一样,可以直接同步调用。
为何常见:因为旧术语“Bridge”太深入人心,人们习惯性地用“老桥升级”来理解新架构,忽略了 JSI 在通信模型上的革命性变化。
误区我听说 Hermes 一开始针对 Android 设计,所以认为新架构在 iOS 上没法用 Hermes。
正解Hermes 早期确实是 Android 优先,但它现在已支持 iOS,并且可以单独开启或关闭。很多跨平台团队在 iOS 上也用 Hermes 来减少启动解析时间。
为何常见:因为早期的官方文档和社区讨论大多以 Android 数据为例,形成了“仅 Android”的刻板印象。
误区代码一行不改,只要打开 newArchEnabled=true,App 启动就会快一倍,滚动也一定更流畅。
正解新架构带来的是“可能性”,不是“保证”。真正的收益来自配合影子树减少重复渲染、用 TurboModules 按需加载、用 Hermes 去掉解析开销;如果代码里仍有大量同步长任务,卡顿依旧会出现。
为何常见:因为技术宣传常强调“更快、更流畅”,大家容易把潜力当成必然结果,忽略了工程优化。
误区Fabric 就是一个绘制引擎,专门让视图绘制速度更快。
正解Fabric 的核心贡献是渲染流程重构:影子树、后台布局、按优先级合批提交、并发渲染能力都依赖它。它的价值不只是“画得快”,而是让 UI 更新可以被调度、被合并、被安排在正确的时机。
为何常见:人们看到“渲染器”三个字,自然会往“画图加速”上联想,而忽略了调度和流水线设计。
面试题
Q1. 旧架构桥接带来的主要开销是什么?
- A.双线程并发问题
- B.异步序列化与排队← 正确答案
- C.原生模块加载慢
- D.渲染更新过于密集
答案:B。旧架构中 JS 与原生通信通过异步 Bridge,消息需要序列化、排队和回调,这正是最典型的瓶颈;其他选项只是可能存在的现象,不是桥的根本问题。
Q2. Hermes 引擎通过什么方式降低启动耗时?
- A.每次启动动态编译
- B.构建期预编译字节码← 正确答案
- C.增加多个引擎线程
- D.跳过原生模块加载
答案:B。Hermes 在构建阶段把 JS 预编译成字节码,设备端省去了解析和 JIT 编译时间;它不是靠多线程或跳过模块来实现提速。
Q3. Fabric 在提交 UI 更新前先构建哪棵虚拟树?
- A.渲染影子树← 正确答案
- B.原生 DOM 树
- C.JSON 对象树
- D.桥接事件树
答案:A。Fabric 先在后台构建影子树,用于描述界面结构并完成布局计算,之后才把结果提交给原生视图;其他选项都不是 Fabric 使用的模型。
Q4. JSI 相比旧桥接最根本的改进是什么?
- A.删除全部原生模块
- B.共享对象引用调用← 正确答案
- C.增加异步消息队列
- D.压缩 JS 网络请求
答案:B。JSI 让 JS 与原生共享宿主对象引用,从而支持同步调用、免序列化;它是新架构替代异步桥的核心机制。
Q5. TurboModules 的核心价值是?
- A.每个模块启动即加载
- B.按需加载与类型安全← 正确答案
- C.完全替代 JavaScript
- D.自动生成 App 图标
答案:B。TurboModules 通过 JSI 按需加载原生模块,并结合代码生成实现类型安全;它的目的不是替代 JS 或生成 UI 资源。
Q6. Fabric 异步渲染的特性描述正确的是?
- A.所有 UI 更新变成同步阻塞
- B.后台布局后按优先级提交← 正确答案
- C.原生组件不再参与绘制
- D.渲染线程完全被移除
答案:B。Fabric 把布局计算放到后台线程,再按优先级合批提交给原生视图,这既能减少 JS 阻塞,又能保证帧率稳定。
Q7. 迁移到新架构时,旧桥接模块的最稳妥策略是?
- A.一次性重写为 C++ 模块
- B.兼容层承载后逐步替换← 正确答案
- C.删除全部旧桥接模块
- D.永久禁止使用新架构
答案:B。新架构提供兼容层让旧桥接模块继续运行,团队应逐步迁移到 TurboModules;一次性重写或删除风险过大。
Q8. 新架构的核心组成部分包括哪些?
- A.JSI 通信层← 正确答案
- B.Fabric 渲染器← 正确答案
- C.Hermes 引擎← 正确答案
- D.AsyncStorage
答案:ABC。新架构的关键组成是 JSI、Fabric 和 Hermes;AsyncStorage 是普通存储库,不属于架构核心组件。
Q9. 影响 Fabric 合帧效率的因素有?
- A.影子树节点的复杂度← 正确答案
- B.后台布局计算耗时← 正确答案
- C.提交优先级与调度← 正确答案
- D.JSON 桥序列化速度
答案:ABC。影子树越复杂、布局越慢、调度不合理都会让合帧变慢;JSON 桥序列化是旧架构的问题,不直接影响 Fabric 合帧。
Q10. 关于 Hermes 的预编译字节码,说法正确的是?
- A.构建期完成编译← 正确答案
- B.减少设备端解析时间← 正确答案
- C.可降低启动内存开销← 正确答案
- D.只能在 Android 使用
答案:ABC。Hermes 在构建期编译成字节码,设备端因此减少解析和编译,既省时又省内存;Hermes 同样支持 iOS,所以 D 错误。