想象你在一家生意火爆的餐厅用餐。老式餐厅里,你和后厨之间隔着一堵厚墙,唯一的沟通方式是传菜窗口:你把想吃的菜写在纸条上,服务员翻译成厨师能懂的术语,塞进窗口排队,厨师做完再通过窗口把菜品和纸条一并递回来。高峰期纸条越积越多,窗口被堵得水泄不通,一盘菜等上十分钟是常事。 React Native 老架构里的 Bridge,就是这样一堵墙。JavaScript(顾客)和原生代码(厨师)被墙隔开,每次通信都要先把数据“写”成 JSON 纸条,排队穿过异步消息队列,到了对岸再“读”出来执行——序列化、反序列化、排队等待,三重损耗叠加,App 一复杂就卡顿。 后来餐厅迎来大翻新:墙上直接开了一扇门,顾客能走进厨房与厨师面对面交流,想吃什么指一下就明白——这就是 JSI。厨房还学会“你点什么才备什么菜”,省下大量食材存货——这就是 TurboModules。黑板菜单也升级成只更新变动的菜名,不再整块擦掉重画——这就是 Fabric。这篇文章,就是带你走一遍这场从“传纸条”到“开直门”的跨平台通信革命。

岗位关联

对 React Native 开发者而言,理解 JSI 与 TurboModules 是吃透新架构性能红利的前提,也是从老架构平滑迁移、定位性能瓶颈的必备底层知识——面试聊到新架构时,这几乎是最硬核的加分项。

目录
  1. 可视化演示
  2. 老桥架构瓶颈
  3. JSI核心机制
  4. TurboModules按需加载
  5. Fabric渲染器
  6. 新架构性能收益
  7. 平滑迁移指南
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。

本节配有交互动效(进入视口后自动加载,约 3KB)。

系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T

老桥架构瓶颈

在传纸条时代,顾客每说一句话都要经过“写纸条—翻译—塞窗口—等待—再传回来”的漫长链路。React Native 老架构里的 Bridge 正是如此:JS 线程想读取本地相册、调用 GPS 或访问数据库时,不能直接触碰原生对象,只能先把方法名和参数打包成一个 JSON 消息,投递到 Bridge 的异步消息队列里。消息在队列里排队,轮到它之后,才被原生线程取走、解析、执行,最后再生成一个 JSON 消息原路返回。

这条链路藏着三个沉重的代价。第一是序列化开销:JS 对象要转成字符串,原生对象要转回结构化数据,数据越大越慢,好比每次点菜都要把整本菜单抄一遍。第二是异步排队:所有线程共用一个消息队列,某个耗时的原生调用会堵住后面所有的消息,就像窗口只有一个,前面的客人迟迟不取餐,后面的全得等着。第三是无谓拷贝:即使只传一个小布尔值,也要走完完整的序列化流程,好比为了一根葱买下整个菜市场的搬运量。

这三重开销叠加,让高频调用场景——比如手势拖拽、动画帧回调、音视频处理——很容易产生肉眼可见的卡顿。理解了这个瓶颈,才能明白新架构为什么要从底层推翻重来。

老架构的悲剧在于:顾客真正等菜的时间(原生执行)只占一小段,其余时间全耗在写纸条和排队上。窗口再快,纸条链路本身的损耗也省不掉。

Tbridge=Tserialize+Tqueue+Tdeserialize+Texecute\displaystyle T_{\text{bridge}} = T_{\text{serialize}} + T_{\text{queue}} + T_{\text{deserialize}} + T_{\text{execute}}
老架构一次通信的总耗时等于序列化、排队、反序列化和原生执行四段耗时的加总——前两段是纯浪费,后一段才是真正干活。
  1. 序列化耗时 $T_{\text{serialize}}$把 JS 参数对象转成 JSON 字符串,数据量越大耗时越长
    Tserialize∝len(JSON(args))\displaystyle T_{\text{serialize}} \propto \text{len}\bigl(\text{JSON}(\text{args})\bigr)
  2. 排队等待 $T_{\text{queue}}$消息进入 Bridge 队列后要等前面的消息处理完,是随机波动的
    Tqueue=∑k=1ntk\displaystyle T_{\text{queue}} = \sum_{k=1}^{n} t_k
  3. 反序列化耗时 $T_{\text{deserialize}}$原生侧把 JSON 字符串解析回可用的类型数据
    Tdeserialize∝len(payload)\displaystyle T_{\text{deserialize}} \propto \text{len}(\text{payload})
  4. 原生执行 $T_{\text{execute}}$真正执行业务逻辑的耗时,这是唯一不可省略的部分
    Texecute=业务固有耗时\displaystyle T_{\text{execute}} = \text{业务固有耗时}

JSI核心机制

餐厅翻新后的关键一步,是拆掉那堵墙,开了一扇直达门。React Native 新架构里的 JSI(JavaScript Interface)就是这扇门——它是一个用 C++ 编写的接口层,横跨在 JS 引擎与原生运行时之间。有了 JSI,JS 不再需要把对象“翻译”成 JSON 纸条,而是直接拿到原生对象的引用:你可以把一个 C++ 原生模块包装成 JS 对象,JS 调用它的方法时,参数以共享引用方式跨语言传递,不经过任何序列化。

理解 JSI 的关键在于“共享引用”四个字。老架构中,数据被拷贝成字符串再拷贝回对象,同一份数据在内存里反复搬家;JSI 则让 JS 引擎和原生代码指向同一块内存,JS 持有一个 C++ 对象的句柄,调用原生函数时直接把句柄传过去,函数返回后同样通过句柄拿结果。这就像顾客和厨师共享同一本食材台账,顾客说“用 3 号柜台那瓶酱油”,厨师直接抬手就够到了,中间没人抄写、没人传话。

由于共享引用,JSI 天然支持同步调用:JS 调原生函数时可以直接拿到返回值,而不必像老 Bridge 那样注册回调等待异步结果。这对手势识别、数据库查询这类“立即要知道答案”的场景是革命性的——门开了,说话即刻有回应。

开门之后,顾客和厨师之间的沟通效率有了质变。但门开了还不够——如果厨房还按老习惯把所有菜都提前做好摆着,照样浪费严重。这就轮到 TurboModules 登场了。

Tjsi≈Texecute≪Tbridge\displaystyle T_{\text{jsi}} \approx T_{\text{execute}} \ll T_{\text{bridge}}
JSI 架构下,通信耗时约等于原生执行本身,相比老 Bridge 省掉了序列化和排队两大块“纯浪费”。
  1. 近似号 $\approx$JSI 仍有一层极薄的函数包装成本,但相对业务执行可忽略
    Toverhead→0\displaystyle T_{\text{overhead}} \to 0
  2. 远小于号 $\ll$表示一个数量级以上的差距,序列化与排队被消灭后总耗时骤降
    Tjsi<0.1×Tbridge\displaystyle T_{\text{jsi}} < 0.1 \times T_{\text{bridge}}
  3. 原生执行 $T_{\text{execute}}$任何架构都消不掉的业务耗时,JSI 把它变成总耗时的主体
    Tjsi=Texecute+Toverhead\displaystyle T_{\text{jsi}} = T_{\text{execute}} + T_{\text{overhead}}

TurboModules按需加载

有了直达门还不够,新餐厅还改变了一个经营习惯:以前厨房会提前把所有菜品都备好半成品,不管客人点不点,食材都在冰箱里占着地方。老架构的 Bridge 也是这样——App 启动时,JS 侧会把所有原生模块全部初始化注册,即使某些模块从未被调用,也白白占着内存和初始化时间。

TurboModules 把这种“全量备菜”改成了“按需上菜”:JS 代码第一次访问某个原生模块时,才真正创建对应的原生实例并缓存起来,后续调用直接复用。想象一下,如果顾客从没点过“佛跳墙”,厨房就完全不需要提前准备那份食材,等真有人点了再下锅也不迟。对应到代码层面,老架构的 NativeModules.Camera 在启动时就存在,新架构则是在 .Camera 第一次被访问时才触发模块构造。

TurboModules 还有一位得力助手叫 Codegen(代码生成器)。它根据一份 TypeScript 或 Flow 编写的接口规范,自动生成 C++ 桥接代码和 JS 侧的类型声明,让 JS 和原生之间的调用契约在编译期就保持类型安全。这好比餐厅把每道菜的配方标准化成电子菜谱,厨师和顾客看的都是同一份文档,不会出现“我要 A 菜,你听成 B 菜”的误会。

按需备菜省下的不只是内存,还有启动时逐个初始化模块的 CPU 时间。这是新架构 App 冷启动速度明显变快的重要原因之一——顾客进门时,厨房只需要为眼前这位客人的菜单做准备。

Mnew=∑i∈Umi    ≤    Mold=∑i=1Nmi\displaystyle M_{\text{new}} = \sum_{i \in U} m_i \;\; \le \;\; M_{\text{old}} = \sum_{i=1}^{N} m_i
新架构的内存占用只包含实际被 JS 调用过的模块,老架构则要把所有模块都背上——省下的内存等于那些“买来从没做过的菜”。
  1. 已用模块集合 $U$JS 首次调用某个模块时才把模块加入集合
    U={ i∣JS 曾调用模块 i }\displaystyle U = \{\, i \mid \text{JS 曾调用模块 } i \,\}
  2. 懒加载求和 $\sum_{i \in U} m_i$只有真正用到的模块才占用内存
    Mnew=m1+m2+⋯+mk\displaystyle M_{\text{new}} = m_1 + m_2 + \dots + m_k
  3. 老架构全量求和 $\sum_{i=1}^{N} m_i$启动时就注册全部 N 个模块
    Mold=Mnew+∑i∉Umi\displaystyle M_{\text{old}} = M_{\text{new}} + \sum_{i \notin U} m_i

Fabric渲染器

除了点餐沟通的升级,新餐厅还换了一块智能黑板菜单。老架构每次 UI 有变化,JS 都要把整棵视图树序列化发给原生层,原生 diff 后再更新——相当于每次改一道菜名,就要把整块黑板擦掉重写一遍,浪费且容易出错。

Fabric 渲染器则把 UI 层整体下沉到 C++ 共享层,JS 通过 JSI 直接操作宿主视图。它还引入了“同步渲染”能力:JS 侧对视图树的更新可以直接同步反映到原生屏幕上,不需要跨线程异步兜圈子。更巧妙的是优先级调度——紧急的 UI 更新(比如手势跟手动画)优先渲染,非紧急的(比如后台数据刷新)可以延后,避免低优先级任务抢占高优先级任务的渲染帧。

用黑板来理解:Fabric 平时只擦掉变化的那一格菜名,写上新的;而且如果顾客正在看黑板,服务员会先更新顾客盯着看的那一行,其他行有空再改。于是 UI 永远跟得上交互,动画不再掉帧,列表滑动不再“飘橡皮筋”。

黑板智能了,渲染路径变短了,UI 响应速度自然水涨船高。把 JSI、TurboModules、Fabric 三件事放到一起看,就是一场从通信到内存再到渲染的全链路改造。

Tfabric=O(∣ΔU∣)    vs.    Tlegacy=O(∣Uall∣)\displaystyle T_{\text{fabric}} = O\bigl(| \Delta U |\bigr) \;\;\text{vs.}\;\; T_{\text{legacy}} = O\bigl(| U_{\text{all}} |\bigr)
新渲染器耗时与变化量成正比,老架构却常要处理整棵视图树。改动越小,新方案的相对优势越明显。
  1. 变化集合 $\Delta U$本次状态变更真正需要重绘的视图节点集合
    ΔU={ 需要更新的视图节点 }\displaystyle \Delta U = \{\, \text{需要更新的视图节点} \,\}
  2. 增量复杂度 $O(| \Delta U |)$耗时只跟变化量成正比,小改动即刻完成
    Tfabric∝∣ΔU∣\displaystyle T_{\text{fabric}} \propto | \Delta U |
  3. 全量复杂度 $O(| U_{\text{all}} |)$老架构往往要遍历整个视图树
    Tlegacy∝∣Uall∣\displaystyle T_{\text{legacy}} \propto | U_{\text{all}} |
  4. 对比关系变化量远小于整棵树时,Fabric 有巨大优势
    Tfabric≪Tlegacy当  ∣ΔU∣≪∣Uall∣\displaystyle T_{\text{fabric}} \ll T_{\text{legacy}} \quad \text{当} \; | \Delta U | \ll | U_{\text{all}} |

新架构性能收益

翻新工程全部落地之后,餐厅的运营数据焕然一新。对 React Native App 来说,收益可以拆成三个可量化的维度。第一是启动加速:TurboModules 让原生模块从“全部初始化”变成“按需初始化”,冷启动时间通常能缩短 20%-50%,具体取决于 App 里有多少从不使用的模块。第二是内存优化:未调用的模块不再常驻内存,低端机上的内存压力明显缓解,OOM 崩溃率随之下降。第三是通信零序列化:JSI 让高频 JS↔原生调用不再有 JSON 开销,手势跟手、动画流畅度、大数据传输这些场景都能感受到质的提升。

这些收益不是零散的,而是环环相扣的:JSI 打开直连通道,TurboModules 减少浪费,Fabric 优化渲染,三者叠加,最终呈现在用户面前的就是“启动更快、滑动更顺、内存更省”的体验。

数字固然漂亮,但真正让团队犹豫的不是收益,而是迁移成本。一家忙碌的餐厅不可能停业三个月装修——好在 React Native 新架构给了你一边营业一边翻新的方案。

Speedup=Told−TnewTold×100%\displaystyle \text{Speedup} = \frac{T_{\text{old}} - T_{\text{new}}}{T_{\text{old}}} \times 100\%
性能提升率等于新旧架构耗时差占老架构耗时的百分比,这一指标可以用来量化迁移新架构的收益。
  1. 老架构耗时 $T_{\text{old}}$一次典型调用的四段链路总耗时
    Told=Tserialize+Tqueue+Tdeserialize+Texecute\displaystyle T_{\text{old}} = T_{\text{serialize}} + T_{\text{queue}} + T_{\text{deserialize}} + T_{\text{execute}}
  2. 新架构耗时 $T_{\text{new}}$JSI 模式下约等于原生执行耗时
    Tnew≈Texecute\displaystyle T_{\text{new}} \approx T_{\text{execute}}
  3. 提升率 Speedup当新架构耗时远小于老架构时,提升率趋近 100%
    Speedup=(1−TnewTold)×100%\displaystyle \text{Speedup} = \left(1 - \frac{T_{\text{new}}}{T_{\text{old}}}\right) \times 100\%

平滑迁移指南

餐厅翻新最理想的方式是“不停业施工”:今天改造大堂的 1 号桌,明天改造 2 号桌,客人始终有地方坐。React Native 新架构的迁移策略正是这个思路——它提供了兼容层(Interop Layer),让老模块和老组件在新架构下依然可以运行。

具体的迁移路径是渐进式的。第一步,开通新架构的开关(在 RN 0.68+ 中通过新架构标志启用),此时 JSI 和 Fabric 已经接管底层,但老模块依赖兼容层照常工作。第二步,按照模块的重要程度和调用频率排序,逐个把原生模块改造成 TurboModules 的规范形态,并用 Codegen 生成类型安全接口。第三步,验证每个模块的行为没有回归,再切换下一个。整个过程中,App 始终处于可发布状态,不需要“停业”。

这套策略的核心智慧在于:让人与系统都有缓冲。老代码不需要一次推翻,新架构的红利也不需要等全部改造完才开始享受——改造完一个模块,就多享受到一份收益。对于团队来说,风险被拆散到每一个小步里,而不是一次性的大爆炸。

从传纸条到开直门,从全量备菜到按需上菜,从整板擦写到增量更新——这座“餐厅”的改造经验,本质上是在讲一个道理:跨语言通信的极致优化,不是把翻译做得更快,而是让双方直接对话。

Adoption=NconvertedNtotal×100%\displaystyle \text{Adoption} = \frac{N_{\text{converted}}}{N_{\text{total}}} \times 100\%
迁移进度等于已转换原生模块数占总模块数的百分比,这个值从 0% 到 100% 都是安全可运行的中间态。
  1. 已完成模块 $N_{\text{converted}}$已迁移到 TurboModules 规范的原生模块数量
    Nconverted≤Ntotal\displaystyle N_{\text{converted}} \le N_{\text{total}}
  2. 总模块数 $N_{\text{total}}$App 中全部原生模块的数量
    Adoption=100%  ⟺  Nconverted=Ntotal\displaystyle \text{Adoption} = 100\% \iff N_{\text{converted}} = N_{\text{total}}
  3. 渐进式区间任意进度下 App 都能通过兼容层正常运行
    0%≤Adoption≤100%\displaystyle 0\% \le \text{Adoption} \le 100\%

AI 应用场景

电商 App 冷启动优化

阶段:性能优化与架构选型

解决的问题:传统电商 App 启动时要初始化几十个原生模块(推送、支付、地图、埋点……),大量模块在首页根本用不到,白白消耗内存和 CPU 时间,冷启动常常卡在启动屏上。TurboModules 的按需加载让 JS 首次访问时才构造模块实例,启动路径只加载首页必需模块,冷启动时间可缩短约 30%,用户流失率随之下降。

具体案例:某跨境电商 App 在 RN 新架构迁移后,启动阶段从 2.8 秒降到 1.9 秒,低端 Android 机上内存占用减少约 80MB,首屏到达率显著提升。

实时音视频通话的帧回调

阶段:高频数据交换与实时渲染

解决的问题:音视频通话中,每一帧画面都需要 JS 与原生之间高频交换数据。老 Bridge 的 JSON 序列化会让帧数据排队积压,导致画面延迟和卡顿。JSI 的同步共享引用让 JS 能直接读写原生帧缓冲,消除了拷贝和序列化延迟。

具体案例:一款跨平台视频会议 App 将图像帧处理迁移到 JSI 后,端到端延迟从 300ms 降到 80ms,弱网环境下的流畅度大幅改善。

原生功能渐进迁移

阶段:技术债清理与架构演进

解决的问题:存量 App 里有几十个老版本原生模块,一次性重写风险极高。通过兼容层,团队可以按模块逐个迁移到 TurboModules,每个模块的改造都在一个独立的 PR 内验证,不影响主干发布节奏。

具体案例:某金融类 App 用了三个迭代周期,把 20 个老模块中的 15 个迁到新架构,期间 App 始终保持每周发版节奏,线上崩溃率未出现回退。

Python 演示

python64 行
import timeimport jsonimport random  class LegacyBridge:    """模拟老版 Bridge:JSON 序列化 + 异步队列"""     def __init__(self, serialize_cost=0.004):        self.serialize_cost = serialize_cost        self.msg_queue = []     def call(self, module, method, args):        time.sleep(self.serialize_cost)  # 序列化        payload = json.dumps({"module": module, "method": method, "args": args})        self.msg_queue.append(payload)        time.sleep(0.003)                # 异步排队        time.sleep(0.002)                # 反序列化        return {"result": "ok"}  class JSI:    """模拟 JSI:同步直接调用,无序列化"""     def __init__(self):        self.modules = {}     def register(self, name, module):        self.modules[name] = module     def call(self, module_name, method, args):        return getattr(self.modules[module_name], method)(*args)  class NativeStorage:    """模拟一个原生本地存储模块"""     def get_item(self, key):        time.sleep(0.002)  # 真实业务执行耗时        return "value:" + key  def benchmark(calls=50):    bridge = LegacyBridge()    jsi = JSI()    jsi.register("storage", NativeStorage())     t0 = time.time()    for i in range(calls):        bridge.call("storage", "getItem", ["key" + str(i)])    t_bridge = time.time() - t0     t0 = time.time()    for i in range(calls):        jsi.call("storage", "get_item", ["key" + str(i)])    t_jsi = time.time() - t0     print("老 Bridge 耗时: %.1f ms" % (t_bridge * 1000))    print("JSI 耗时:      %.1f ms" % (t_jsi * 1000))    print("性能提升:      %.1f%%" % ((t_bridge - t_jsi) / t_bridge * 100))  if __name__ == "__main__":    benchmark()
目的:用 Python 模拟老版 Bridge 与 JSI 两种架构,对比 50 次原生调用的耗时差异,直观量化“消灭序列化”带来的性能提升。
  1. bridge.call(...)走完整链路:序列化、入队、反序列化、执行
  2. jsi.call(...)直接通过对象引用调用原生方法,无序列化
  3. json.dumps(...)模拟老架构的 JSON 序列化开销
  4. msg_queue.append(payload)模拟异步消息队列排队
  5. jsi.register(...)模拟 TurboModules 的模块注册表
  6. getattr(self.modules[...])(*args)JSI 直连调用的核心:按名取对象然后直接执行

常见误区

误区新架构有了 JSI,JS 和原生之间就再也没有桥的概念了,通信成本为零,随便怎么调用都行。

正解JSI 本质上仍然是“桥接层”,只不过它把老 Bridge 的异步 JSON 纸条通道换成了同步的共享引用通道。序列化没了,但每次跨语言调用仍有一层 C++ 函数包装和类型转换成本;在极高频的逐帧调用中,仍需注意批量处理和后台线程调度。就像门开了,但推门和迈步还是要花力气的。

为何常见:很多人把“消灭序列化”理解成“消灭一切通信成本”,忽略了 JSI 函数调用本身也是一次跨语言边界操作。

误区只要打开新架构开关,项目里所有老原生模块都会自动变成 TurboModules,性能自动提升。

正解TurboModules 需要模块本身按规范改造,并用 Codegen 生成类型安全的 JSI 接口。老模块在兼容层下虽然能运行,但享受不到懒加载和直连调用的红利。改造一个模块,才多享受一份收益——不是开关一开魔法就来。

为何常见:新架构的“兼容”让老代码能跑,容易让人误以为兼容等于已升级。

误区Fabric 的核心改进就一个字“快”,因为它把异步渲染变成了同步渲染。

正解同步渲染只是 Fabric 的一部分,更重要的是它把 UI 层下沉到 C++ 共享层,让 JS 与原生共享视图树,并支持优先级调度——紧急交互优先渲染,非紧急更新延后处理。同步是手段之一,共享和调度才是架构级变化。

为何常见:大家习惯用“异步改同步”来概括渲染性能优化,忽略了 Fabric 底层数据结构和调度策略的变革。

误区老项目想用新架构,必须把所有原生模块、自定义组件全部推翻重写,工程量巨大,所以一直不敢动手。

正解RN 新架构提供了完整的兼容层,老模块在老 Bridge 语义下照常工作,团队可以按模块逐个迁移,每次改动都能独立发布验证。渐进式迁移就是为存量 App 设计的,不是二选一的生死抉择。

为何常见:把“架构升级”想象成全量重构,忽略了官方兼容层的存在。

误区JSI 听起来像是一个 JS 库,应该用 npm 装一下就能用。

正解JSI(JavaScript Interface)是嵌入在 React Native 底层 C++ 核心中的接口层,它定义了 JS 引擎与宿主环境如何互相暴露对象和函数。开发者通常不直接写 JSI 代码,而是通过 TurboModules 和 Codegen 间接使用它。它更像墙壁上的门框,是装修的一部分,不是客人的 app。

为何常见:名字里带着 JavaScript 字样,容易让人误以为是 JS 生态的普通库。

面试题

Q1. JSI 的核心作用是什么?

单选题 · easy

  • A.替代 JS 引擎执行所有 JS 代码
  • B.让 JS 与原生共享引用并直接调用← 正确答案
  • C.把 JS 编译成原生机器码运行
  • D.将原生代码转译成 JS 字节码

答案:B。JSI 是 C++ 接口层,它让 JS 引擎与原生运行时互相持有对方对象的引用,JS 可直接调用原生函数,无需 JSON 序列化。A、C、D 描述的分别是引擎替换、编译器、转译器的职能,与 JSI 无关。

Q2. 老版 Bridge 存在哪些性能瓶颈?

多选题 · mid

  • A.JSON 序列化和反序列化开销← 正确答案
  • B.异步消息队列的排队等待← 正确答案
  • C.启动时全量注册所有原生模块← 正确答案
  • D.不支持 JavaScript 基础语法

答案:ABC。老架构每次通信都要序列化、排队、反序列化,且启动时全部模块注册,这三点都是性能瓶颈。D 与事实相反,老架构完全支持 JS 语法,瓶颈在通信层而非语言层。

Q3. TurboModules 最核心的设计思想是?

单选题 · mid

  • A.启动时注册全部原生模块
  • B.首次使用时才创建模块实例← 正确答案
  • C.把原生模块转成 WebAssembly
  • D.由开发者手动管理模块队列

答案:B。TurboModules 的核心是懒加载——JS 首次访问某模块时才构造原生实例,从而降低启动成本和内存占用。A 是老架构行为,C 张冠李戴,D 在真实架构中不存在。

Q4. 关于 JSI,下列说法正确的是?

多选题 · hard

  • A.JSI 是使用 C++ 编写的接口层← 正确答案
  • B.JSI 仍然需要 JSON 序列化
  • C.JSI 支持同步调用原生函数← 正确答案
  • D.JSI 只能在 iOS 平台上运行

答案:AC。JSI 是 C++ 编写的跨平台接口层,支持 Android 和 iOS;它通过共享引用实现同步调用,彻底摆脱 JSON 序列化。B 描述的是老 Bridge 的机制,D 忽略了 JSI 的跨平台特性。

Q5. Fabric 渲染器的主要改进是什么?

单选题 · mid

  • A.将 UI 逻辑从原生层移回 JS
  • B.C++ 共享层支持同步渲染和优先级← 正确答案
  • C.每帧全量重建整棵视图树
  • D.使用 WebView 渲染所有组件

答案:B。Fabric 把 UI 层下沉到 C++ 共享层,支持同步渲染和优先级调度,只更新变化的视图节点。A 方向反了,C 是老架构的劣势,D 则完全是另一种技术路线。

Q6. 新架构中消除序列化开销的关键技术是?

单选题 · easy

  • A.Bridge
  • B.JSI← 正确答案
  • C.CodePush
  • D.WebView

答案:B。JSI 通过共享对象引用的方式让 JS 直接调用原生函数,省去了 JSON 序列化和反序列化。Bridge 是产生开销的老机制,CodePush 是热更新工具,WebView 是网页容器,都与序列化消除无关。

Q7. 为什么 JSON 序列化会拖慢通信速度?

多选题 · mid

  • A.字符串解析需要额外 CPU 时间← 正确答案
  • B.大对象拷贝占用内存带宽← 正确答案
  • C.序列化过程增加端到端延迟← 正确答案
  • D.序列化会导致 JS 线程崩溃

答案:ABC。JSON 序列化要遍历对象转字符串,原生侧再解析回对象,既消耗 CPU 又拷贝内存,整体延迟自然增加。D 夸大其词,序列化慢但不会必然导致崩溃,崩溃风险来自内存峰值而非序列化本身。

Q8. 以下哪项是老架构平滑迁移到新架构的正确策略?

单选题 · hard

  • A.必须一次性重写所有原生模块
  • B.利用兼容层逐模块渐进迁移← 正确答案
  • C.彻底移除所有原生 API 调用
  • D.降级到旧版本 React Native

答案:B。官方提供了 Interop Layer 兼容层,老模块可在新架构下运行,团队按优先级逐步迁移模块,每个阶段都可发布。A 风险过大,C 不现实,D 是走回头路,都没利用新架构的渐进迁移设计。

Q9. Codegen 在 TurboModules 中的作用是什么?

单选题 · easy

  • A.生成类型安全的原生模块接口← 正确答案
  • B.压缩 JS bundle 的代码体积
  • C.自动优化所有渲染性能
  • D.把 TypeScript 编译成 Java

答案:A。Codegen 根据接口规范同时生成 C++ 桥接代码和 JS 类型声明,让调用契约在编译期可校验。B、C、D 分别是打包、渲染优化、编译器的职责,与 TurboModules 的接口生成无关。

Q10. 新架构性能收益主要来自哪些方面?

多选题 · extreme

  • A.启动时按需加载原生模块← 正确答案
  • B.消灭通信中的 JSON 序列化← 正确答案
  • C.渲染层支持优先级调度← 正确答案
  • D.完全移除 JS 引擎的 GC 机制

答案:ABC。TurboModules 按需加载缩短启动时间并降低内存,JSI 消灭序列化降低通信延迟,Fabric 优先级调度提升 UI 流畅度,三者共同构成新架构收益。D 是臆想,JSI 和 TurboModules 都不涉及移除 JS 引擎的垃圾回收机制,GC 是 JS 引擎自身行为。