想象两个隔海相望的邻国。东边的「JS 国」人人说 JavaScript,擅长画设计图纸;西边的「原生国」里住着 Android 城和 iOS 城两大家族,坐拥最好的建材和施工队。两国想合作盖楼——JS 国负责把界面设计成图纸,原生国负责把图纸盖成真正的楼。可问题来了:语言不通,隔海相望,图纸怎么送过去?于是两国共同修建了一座「跨海大桥」,并成立了一家「翻译快递公司」——Bridge。每个界面元素(按钮、文本、列表)都是图纸上的一个符号,要变成原生国里真实的 UI 控件,必须经历打包(ViewManager 封装)、翻译(序列化)、运输(消息队列)、施工(原生渲染)四个环节。旧架构下快递慢、还会堵车;新架构(Fabric + TurboModule)干脆铺了海底光缆。本文就带你沿着这座大桥走一圈,看懂 React Native 如何把 JS 组件变成手机上真正顺滑的界面。

岗位关联

理解 React Native 桥接与组件封装,是移动端跨平台开发、混合应用架构设计与性能优化的核心基本功,也是晋升资深前端/移动端工程师的必考知识点。

目录
  1. 可视化演示
  2. 桥接架构全景
  3. ViewManager封装:把原生特产装进统一包装盒
  4. 虚拟DOM映射:从图纸到真楼
  5. Bridge性能瓶颈:快递公司遇上高峰期
  6. Fabric新架构:从书信往来升级为光缆直连
  7. TurboModule优化:随取随用的贵宾通道
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

演示React Native与原生UI的桥接机制:Bridge异步通信流程、Fabric新架构同步渲染改进,以及TurboModule性能优化方案对比。

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

RN Bridge异步通信机制 JS线程通过Bridge序列化消息发送至原生线程 Bridge异步批处理导致通信延迟 ViewManager将JS组件映射为原生UI视图 Bridge=Serialize→Queue→Deserialize Bridge架构实现跨平台渲染

桥接架构全景

快递公司开张第一天,桥上只有一条规则:所有包裹必须用统一的「国际标准箱」打包,贴上双方都认得的标签,才能过桥。JS 国把要传的话写进包裹,快递员背着包裹过桥,交给原生国海关;海关拆包、翻译、执行,再把结果包成新包裹,快递员背回去。这套「翻译 + 快递」的体系,就是 React Native 旧架构里大名鼎鼎的 Bridge。

Bridge 的官方定位是「JS 与原生运行时之间的异步桥接层」。JS 侧每调用一个原生方法(比如弹 Toast、获取定位),都会被封装成一个消息,塞进消息队列。Bridge 采用批量处理策略,攒够一批消息才统一发送,以减少过桥次数。原生侧执行完后,把结果同样以消息形式回传。所有通信都是异步的,JS 拿不到「立即返回值」,只能通过回调或 Promise 获取结果。

一次完整的桥接调用要经历四个阶段:序列化(把参数翻译成 JSON)、传输(过桥)、反序列化(原生侧解析)、执行(真实调用)。每一步都有耗时。假如一个页面要显示 100 个组件,启动时就可能有上千条消息在队列里排队。

回头再看上面这个公式,你会发现快递公司的每一步都在「花钱」。设计师画得越快,桥上的包裹积压越多。所以 React Native 团队一直在想:能不能少过桥?能不能改造桥?这就是后文的故事。

Tbridge=Tserialize+Ttransfer+Tdeserialize+Texec\displaystyle T_{\text{bridge}} = T_{\text{serialize}} + T_{\text{transfer}} + T_{\text{deserialize}} + T_{\text{exec}}
总时延 = 打包时间 + 过桥时间 + 拆包时间 + 执行时间。任何一步卡壳,整个 UI 都会等待。
  1. T_serialize 序列化阶段JS 将函数名和参数整理成 JSON 字符串,相当于把要说的话写进标准箱。
    Tserialize=∑k=1m(len(keyk)+len(valuek))\displaystyle T_{\text{serialize}} = \sum_{k=1}^{m} \left( \text{len}(\text{key}_k) + \text{len}(\text{value}_k) \right)
  2. T_transfer 传输阶段消息在通信线程上排队并过桥,耗时与消息数量和桥的带宽直接相关。
    Ttransfer=Nmsgs×SavgBandwidth\displaystyle T_{\text{transfer}} = \frac{N_{\text{msgs}} \times S_{\text{avg}}}{\text{Bandwidth}}
  3. T_deserialize 反序列化阶段原生侧把 JSON 解析成可执行的对象,开销随消息体变大而增加。
    Tdeserialize=α×Spayload\displaystyle T_{\text{deserialize}} = \alpha \times S_{\text{payload}}
  4. T_exec 执行阶段原生代码真正运行,比如弹 Toast、创建视图,后续动画更新也在此完成。
    Texec=∑i=1rti\displaystyle T_{\text{exec}} = \sum_{i=1}^{r} t_i

ViewManager封装:把原生特产装进统一包装盒

原生国有很多「特产」,Android 城有 TextView、Button,iOS 城有 UILabel、UIButton。它们各自长得很不一样,JS 国的设计师根本叫不出名字。于是两国海关立了规矩:每件特产必须由一位「封装专员」标准化打包——这位专员就是 ViewManager。它负责给每个原生视图写上「说明书」(属性)、装上「对讲机」(事件)、贴上「物料号」(注册名),让 JS 国的人只要报出编号就能下单。

在 React Native 中,每个可被 JS 使用的原生视图组件背后都有一个 ViewManager。它继承自 ViewManager 基类,核心职责有三:createViewInstance 方法负责创建原生视图实例;@ReactProp 注解把 JS 侧的 props 映射到原生属性的 setter;事件发射器把原生侧的用户交互(点击、滑动)反向传给 JS。这套「创建 + 映射 + 事件」的标准流程,正是「原生 UI 组件封装」的本质。

自定义一个原生组件的完整链路:先写原生类继承 ViewManager,重写 getName 返回注册名(如 “MyTextView“);接着用 @ReactProp(name = ”text”) 暴露属性;再实现 createViewInstance 指定构造方式;然后创建一个 ReactPackage,把 ViewManager 加进 createViewManagers 列表,在 MainApplication 的 getPackages 中注册;最后 JS 侧用 requireNativeComponent('MyTextView') 拿到组件直接使用。官方预置的 <Text>、<View> 底层正是这套机制的产物。

有了 ViewManager 这位封装专员,JS 设计师完全不必了解 Android 和 iOS 的差异——他只要报出「条形码」,就能在图纸上画出原生国最地道、最流畅的控件。这正是跨平台开发的浪漫:一次设计,两处施工。

JSComponent→registerViewManager→createViewViewInstance×Props×Events\displaystyle \text{JSComponent} \xrightarrow{\text{register}} \text{ViewManager} \xrightarrow{\text{createView}} \text{ViewInstance} \times \text{Props} \times \text{Events}
一个 JS 组件 = 原生视图实例 + 属性映射 + 事件回调的三元组。ViewManager 负责三者的标准装配。
  1. register 注册环节ViewManager 通过 getName 提供全局唯一名字,就像给特产贴上条形码。
    JSName=ViewManager.getName()\displaystyle \text{JSName} = \text{ViewManager.getName()}
  2. createView 创建环节createViewInstance 在原生侧生成真实视图对象,等待属性和子节点填充。
    view=createViewInstance(context)\displaystyle \text{view} = \text{createViewInstance}(\text{context})
  3. props/events 装配环节@ReactProp 把 JS 传入的属性写进视图,事件回调把原生交互传回 JS。
    view.setProp(key,value);event→JS\displaystyle \text{view}.\text{setProp}(\text{key}, \text{value}); \quad \text{event} \to \text{JS}

虚拟DOM映射:从图纸到真楼

设计师画好图纸后,接下来是「按图施工」。不过图纸到真楼之间不能整本重画——那样太浪费。JS 国发明了一种聪明的办法:先在心里生成一份「电子蓝图」(Virtual DOM Tree),每次改动先在电子蓝图里比对,找出和上一版不一样的地方,只把差异部分做成「补丁」送过桥去,施工队只需按补丁修改。

React Native 沿用 React 的虚拟 DOM + Diff 机制。JS 侧每次 setState 触发重新渲染后,React 通过 Diff 算法比较新旧两棵虚拟组件树,生成一棵「差异补丁树」。这份补丁随后被序列化成 UIManager 能识别的指令——createView、setChildren、manageChildren、updateProperties 等,通过 Bridge 发给原生侧。原生侧的 UIManagerModule 再按指令逐个创建、更新、删除真实视图。

Diff 算法的复杂度被优化到接近线性,它基于两个假设:相同类型的组件生成相同的树形结构,同层节点只需同层对比。这样一来,虚拟树 → 差异补丁 → 原生指令 → 真实 UI 更新的链路很短,大部分 UI 操作不需要触碰原生代码,这就是「一次编写、到处运行」得以流畅的幕后功臣。

有了「电子蓝图 + 差异补丁」,快递公司的工作量骤减——设计师不再整本图纸过桥,只递一页修改单。Bridge 上从前车水马龙,如今只跑最关键的那几辆快递车。

O(diff)=O(n),∣patch∣≪Nnodes\displaystyle O(\text{diff}) = O(n), \quad |\text{patch}| \ll N_{\text{nodes}}
Diff 的时间复杂度与节点数线性相关,而真正跨桥传输的补丁远小于整棵树的节点总数。
  1. Diff 时间复杂度React 逐层对比虚拟树,每一层的对比代价与节点数量成正比。
    O(diff)=O(n)\displaystyle O(\text{diff}) = O(n)
  2. 补丁大小只有变化的节点被列入补丁,数量远小于整棵树的节点总数。
    ∣patch∣=∑i=1dΔni\displaystyle |\text{patch}| = \sum_{i=1}^{d} \Delta n_i
  3. 指令执行原生 UIManager 按照补丁逐条执行,完成真实视图的增删改。
    UInew=UIold+patch\displaystyle \text{UI}_{\text{new}} = \text{UI}_{\text{old}} + \text{patch}

Bridge性能瓶颈:快递公司遇上高峰期

生意越做越大,桥的缺陷也暴露了。所有包裹都要在 JS 国的「打包站」和原生国的「海关」之间反复排队;每个包裹都强制用标准箱(JSON),哪怕只说一句「Hello」也要包上厚厚泡沫;更麻烦的是,快递员只能单向传递,设计师在 JS 国永远无法当场知道包裹是否签收。

Bridge 的三大先天瓶颈:其一,序列化开销——每一条通信都要经过 JSON.stringify 和 JSON.parse,数据越大开销越高;其二,异步队列——JS 与原生无法共享内存,调用后必须等消息回传,高频交互(如连续拖拽)会产生大量积压消息;其三,批量机制——为了效率而批量发送,却让交互实时性变差,用户滑动列表时能明显感到「粘滞感」。

从数据上看,桥接时延与消息数量和单条消息体量几乎成正比。一个复杂的启动页面可能触发上千条 UIManager 指令消息,每条都要序列化、过桥、反序列化。滚动列表时,每秒可能产生 60 帧的布局指令,一旦消息队列堆积,UI 线程就会被「喂饱」,掉帧和卡顿随之而来。

快递公司终于意识到:光靠增加快递员是治标不治本。要根治拥堵,必须修一条更快的路——于是,两国决定铺设海底光缆,开启新架构时代。

Tdelay∝Nmessages×(Spayload+Cqueue)\displaystyle T_{\text{delay}} \propto N_{\text{messages}} \times \left( S_{\text{payload}} + C_{\text{queue}} \right)
时延 ≈ 消息条数 ×(单条大小 + 排队代价)。大桥越忙,每件快递就越慢。
  1. 消息数量一次渲染会产生成百上千条指令消息,数量直接放大总时延。
    Nmessages∼O(nodes)\displaystyle N_{\text{messages}} \sim O(\text{nodes})
  2. 单条体量JSON 序列化后的大小,随属性个数和字符串长度增长。
    Spayload=∑props(len(key)+len(value))\displaystyle S_{\text{payload}} = \sum_{\text{props}} \left( \text{len}(\text{key}) + \text{len}(\text{value}) \right)
  3. 排队代价队列越长,每条消息等待处理的时间越久,时延呈非线性增长。
    Cqueue=∑i=1ki×t0\displaystyle C_{\text{queue}} = \sum_{i=1}^{k} i \times t_0

Fabric新架构:从书信往来升级为光缆直连

工程队带来了两项黑科技:一条「海底光缆」(JSI)和一套「全新建楼指挥系统」(Fabric)。以前设计师要通过快递把话说清楚再收到回复;现在光缆直接连到原生国,设计师拿起电话就能实时指挥施工,不用再等包裹一来一回。

Fabric 是 React Native 的新渲染架构。它的核心是 JSI(JavaScript Interface)——一个用 C++ 实现的轻量接口,允许 JS 引擎直接持有 C++ 对象和原生对象引用,实现同步调用,彻底绕开 JSON 序列化和异步消息队列。在 Fabric 下,组件渲染从「JS → Bridge → 原生」变成「JS → C++ 渲染器 → 原生」,中间层大幅瘦身。

Fabric 重构了两大管线:渲染流水线和事件处理。渲染时,组件树在 C++ 层直接生成 Shadow Tree,并同步到原生视图;事件处理不必从 JS 发起,原生事件通过 JSI 直接触发 JS 回调。此外,Fabric 支持优先级调度,用户交互(如触摸)的渲染优先级高于后台动画,保证响应式体验。这套机制是跨平台的——Android 和 iOS 共用同一套 C++ 渲染核心。

海底光缆让「过桥」成了历史——设计师一个电话,施工队原地开工。Fabric 正是这样把 RN 的渲染速度拉回原生水准,也让新一代 RN 应用在复杂动画面前不再露怯。

ΔTrender=Tbridge−Tjsi→min⁡\displaystyle \Delta T_{\text{render}} = T_{\text{bridge}} - T_{\text{jsi}} \to \min
渲染时延的优化目标 = 消除桥接的序列化与往返排队,让渲染时延趋近于纯原生调用。
  1. bridge 时延旧架构渲染一帧的时间包含序列化、传输、反序列化的总和。
    Tbridge=Ts+Tt+Td+Te\displaystyle T_{\text{bridge}} = T_s + T_t + T_d + T_e
  2. JSI 时延新架构下 JS 直接同步调用 C++ 层,只剩执行时间。
    Tjsi=Te\displaystyle T_{\text{jsi}} = T_e
  3. 优化目标两者之差越小,渲染速度越接近原生水准。
    ΔTrender=Tbridge−Tjsi→0\displaystyle \Delta T_{\text{render}} = T_{\text{bridge}} - T_{\text{jsi}} \to 0

TurboModule优化:随取随用的贵宾通道

光缆修好后,另一个问题浮出水面:原生国海关大楼里,所有办事窗口(原生模块)每天一上班就全部亮灯待命——哪怕这一天根本没人来办理业务。TurboModule 带来的改变是:给常用模块开「贵宾窗口」,其他窗口随叫随开。用到哪个模块,才实时初始化哪个,绝不让无用模块白占资源。

TurboModule 是 RN 新架构下原生模块的加载与调用方案。旧架构中,所有原生模块在应用启动时一次性加载并注册,启动成本与模块总数成正比;TurboModule 则采用懒加载策略,在 JS 首次访问某个模块时才创建其实例,并通过 JSI 将原生方法直接暴露给 JS,调用时不再经过序列化。

实现层面,TurboModule 利用 JSI 生成「类型安全」的绑定代码。开发者在原生侧定义模块规范(Spec),构建时自动生成 JS 侧对应的接口。JS 调用 TurboModule 方法时,参数直接传入 C++ 层,返回值同步可得。由于不再有异步等待,高频调用(如读取传感器数据、频繁弹窗)的延迟被压缩到微秒级。启动性能的提升同样明显——应用启动时加载的模块数从「全部」降为「必经的少数几个」。

TurboModule 就像把那个「全员待命」的海关大楼改成了「随需开放」的智能大厅——人气高的模块走贵宾通道,冷门的模块按需开门。省下的电力和人力,就是 App 启动时省下的每一毫秒。

Tstartup∝Nloaded×Tinit\displaystyle T_{\text{startup}} \propto N_{\text{loaded}} \times T_{\text{init}}
启动时间与实际加载的模块数量成正比。TurboModule 把 N_loaded 从「全部」砍到「被用到」,启动自然变快。
  1. 模块总数旧架构启动时所有模块一起初始化,总量等于注册数。
    Nloaded=Ntotal\displaystyle N_{\text{loaded}} = N_{\text{total}}
  2. 懒加载新架构只加载 JS 侧真正引用的模块,其余按需实例化。
    Nloaded=Nused\displaystyle N_{\text{loaded}} = N_{\text{used}}
  3. 调用时延JSI 同步直调让单次调用时延与纯原生函数相当。
    Tcall=Tnative+O(1)\displaystyle T_{\text{call}} = T_{\text{native}} + O(1)

AI 应用场景

地图 SDK 的原生组件封装

阶段:移动端跨平台集成 / 原生能力封装

解决的问题:传统 WebView 方案加载地图 JS SDK,首屏慢且交互延迟明显。通过 ViewManager 封装高德原生地图 SDK,JS 侧直接使用 <AMapView> 组件,地图渲染走原生管线,拖拽缩放的流畅度提升数倍,多指手势响应接近纯原生体验。

具体案例:某外卖 App 需要在 iOS/Android 双端展示骑手配送轨迹。团队编写 AMapViewManager,暴露 center、zoom、markers 属性,通过 onMarkerClick 事件回传点击坐标,JS 侧无感知双端差异,一套业务代码双端上线。

支付 SDK 的 TurboModule 改造

阶段:原生模块性能优化

解决的问题:旧 Bridge 下调起支付要经历多轮异步消息往返,耗时可达数百毫秒;改用 TurboModule 后,JS 直接同步调用原生支付方法,参数直达原生层,收银台秒开。

具体案例:电商 App 将支付模块迁移到 TurboModule,仅加载被调用的支付模块,冷启动时间降低 18%,支付唤起耗时从 350ms 降至 40ms,用户付款环节流失率显著下降。

长列表 Fabric 迁移提升流畅度

阶段:渲染架构升级

解决的问题:长列表在旧的异步 Bridge 下滚动掉帧,用户滑动时能看到明显卡顿。迁移到 Fabric 后,渲染指令走 JSI 同步直连 C++ 层,配合优先级调度,列表滚动可稳定在 60fps。

具体案例:社交 App 的信息流页面包含图片、视频、点赞按钮等混合组件,迁移后滚动帧率从 38fps 提升至 59fps,崩溃率下降 22%。

Python 演示

python57 行
import jsonimport random  class Bridge:    """模拟 RN 旧架构的 Bridge 异步桥接层。"""     def __init__(self, batch_size=5):        self.queue = []        self.batch_size = batch_size        self.calls = 0        self.total_latency = 0.0     def call_native(self, module, method, args):        msg = json.dumps({"module": module, "method": method, "args": args})        self.queue.append(msg)        self.calls += 1        if len(self.queue) >= self.batch_size:            return self.flush()        return None     def flush(self):        payload = sum(len(m) for m in self.queue)        latency = 0.1 + payload * 0.001 + self.calls * 0.002        self.total_latency += latency        self.calls = 0        self.queue.clear()        return latency  class JSI:    """模拟 RN 新架构 JSI 的同步直连调用。"""     @staticmethod    def call_native(module, method, args):        return 0.001 + random.random() * 0.002  def simulate(calls=200):    bridge = Bridge(batch_size=10)    old_latency = 0.0    for i in range(calls):        lat = bridge.call_native("Toast", "show", ["msg_%d" % i, "short"])        if lat is not None:            old_latency += lat     new_latency = 0.0    for i in range(calls):        new_latency += JSI.call_native("Toast", "show", ["msg_%d" % i, "short"])     print("[Old Arch] Bridge 总时延: %.4f 秒" % old_latency)    print("[New Arch] JSI 总时延: %.4f 秒" % new_latency)    print("[Speedup] 提升倍数: %.1fx" % (old_latency / new_latency))  if __name__ == "__main__":    simulate(200)
目的:用 Python 模拟 RN 旧架构 Bridge 的「批量打包 + JSON 序列化」通信与新版 JSI「同步直连」通信,对比两者的总时延与加速比。
  1. self.queue = []模拟 Bridge 的消息队列,JS 侧调用先入队等待。
  2. msg = json.dumps({...})模拟序列化环节,把调用参数打成 JSON 包裹。
  3. if len(self.queue) >= self.batch_size模拟批量发送机制,攒够一批才过桥。
  4. latency = 0.1 + payload * 0.001 + self.calls * 0.002时延由固定开销、消息体量、排队代价三部分组成。
  5. class JSI模拟新架构的同步直连层,无需序列化,直接返回微秒级延时。
  6. return 0.001 + random.random() * 0.002模拟纯原生执行耗时,无打包过桥成本。
  7. for i in range(calls)分别驱动两种架构完成相同次数的调用。
  8. old_latency / new_latency计算新旧架构的加速比,直观展示优化收益。

常见误区

误区「React Native 页面就是一个嵌在 App 里的网页,用 WebView 渲染的,所以我才能直接写 HTML 标签。」很多新手把 RN 与 Cordova、Ionic 混为一谈。

正解RN 渲染的是真正的原生控件。JS 代码通过 Bridge 或 Fabric 驱动的是 Android/iOS 自带的 View、TextView、Button。用 WebView 渲染的是另一类 Hybrid 技术。RN 的「跨平台」是把 JS 声明映射成本地原生组件,而不是在 Web 里画界面。

为何常见:因为 RN 用 JS 写界面,外表很像网页开发,新手容易把「编程语言」和「渲染方式」画等号。

误区「我在 JS 里调用了一个原生方法,下一秒就能在下一行代码里用返回结果。」初学 RN 时误以为跨桥调用和普通 JS 函数一样是同步的。

正解旧架构 Bridge 是严格异步的。JS 调用原生方法后立即返回「未定义」,结果只能通过回调函数或 Promise 在未来的某个时间点拿到。新版 JSI 才支持同步调用,但这是架构升级后的能力,并非 Bridge 的特性。

为何常见:日常写 JS 函数几乎都是同步的,惯性思维让人忽略跨语言调用必然涉及消息往返。

误区「RN 提供了 requireNativeComponent,所以只写 JS 就能封装原生组件。」新手认为封装 UI 是纯前端工作。

正解requireNativeComponent 只是桥接的「收件端」。真正的封装工作在原生侧:要写 ViewManager 子类、用 @ReactProp 声明属性、注册事件、放进 ReactPackage 并完成全局注册。省略任何一步,JS 侧都会报「组件找不到」。

为何常见:RN 官方把封装接口封装得比较友好,JS 开发者误以为不需要碰原生代码。

误区「新架构用 JSI 同步调用,那 JS 里所有函数都会同步阻塞,性能岂不是更差?」有同学因此担心新架构反而变慢。

正解JSI 只让「JS 与 C++/原生边界」的调用变成同步直连,JS 本身的单线程事件循环模型没有改变。业务代码中大部分操作仍然是异步的,只有跨语言边界调用成为快速的同步访问,这恰恰是性能提升的关键。

为何常见:把「JSI 同步调用」扩大理解成「JS 引擎整体变同步」,混淆了语言执行模型与跨语言调用机制。

误区「TurboModule 就是把原来的模块注册表改个名字,性能和以前没区别。」有人看到 API 调用形式变化不大便得出此结论。

正解TurboModule 是架构级重构:结合 JSI 彻底去掉序列化与反序列化,用懒加载替代全量加载,用代码生成替代运行时反射。启动速度和调用时延的改善是数量级的,而非表面优化。

为何常见:API 表面相似掩盖了底层实现差异,不了解 JSI 和 C++ 层的机制就难以看出本质区别。

面试题

Q1. RN 中 JS 与原生通信的主要通道是?

单选题 · easy

  • A.Bridge 异步消息队列← 正确答案
  • B.WebView 脚本注入
  • C.HTTP 长轮询通信
  • D.共享内存直访模式

答案:A。RN 旧架构通过 Bridge 异步消息队列完成 JS 与原生通信,消息经序列化后跨桥传输。WebView 注入属于 Hybrid 方案,HTTP 轮询与共享内存并非 RN 的通信机制。

Q2. 在 RN 中负责创建原生视图实例的管理类是?

单选题 · easy

  • A.ViewManager← 正确答案
  • B.TurboModule
  • C.ReactPackage
  • D.NativeModule

答案:A。ViewManager 专门负责原生视图的创建、属性映射与事件管理;TurboModule 管理原生模块;ReactPackage 负责注册打包;NativeModule 是模块基类。视图层面的管理核心是 ViewManager。

Q3. ViewManager 向 JS 侧暴露属性的方式是?

单选题 · mid

  • A.@ReactProp 注解← 正确答案
  • B.@Override 重写
  • C.@interface 声明
  • D.@Inject 注入

答案:A。ViewManager 通过 @ReactProp(name = "……") 注解声明属性映射,JS 侧传入的 props 会找到对应 setter 写入原生视图。其他选项分别是 Java 重写、接口声明、依赖注入,与 RN 属性映射无关。

Q4. 旧 Bridge 架构的通信瓶颈包括?

多选题 · mid

  • A.JSON 序列化开销← 正确答案
  • B.异步消息队列积压← 正确答案
  • C.控件绘制效率低
  • D.动态语言执行慢

答案:AB。Bridge 的核心瓶颈是每条消息都要 JSON 序列化/反序列化,且异步队列在高速交互下会积压消息导致掉帧。控件绘制效率和 JS 语言执行速度不是 Bridge 引入的瓶颈。

Q5. Fabric 新架构的核心改进方向是?

单选题 · mid

  • A.引入 JSI 直连调用← 正确答案
  • B.用 WebView 替代渲染
  • C.删除全部原生代码
  • D.改用纯 C++ 写 JS

答案:A。Fabric 的关键是引入 JSI,让 JS 与 C++/原生层同步直连,免去序列化和异步队列。它并未替代原生渲染,也没有删除原生代码,更没有改变 JS 语言本身。

Q6. 关于 TurboModule 的正确说法是?

多选题 · hard

  • A.采用懒加载按需初始化← 正确答案
  • B.通过 JSI 暴露原生方法← 正确答案
  • C.仍需 JSON 序列化参数
  • D.只能在 Android 平台用

答案:AB。TurboModule 的核心特性是懒加载和基于 JSI 的类型安全绑定,调用不再需要 JSON 序列化。它是跨平台方案,Android 和 iOS 都支持,C 选项恰好是它要消除的旧架构开销。

Q7. JS 侧引用自定义原生组件的 API 是?

单选题 · easy

  • A.requireNativeComponent← 正确答案
  • B.createNativeElement
  • C.importNativeModule
  • D.useBridgeComponent

答案:A。JS 侧通过 requireNativeComponent('注册名') 获取封装好的原生组件。其余选项并非 RN 暴露给开发者的真实 API,属于干扰项。

Q8. 自定义原生组件的注册流程包含?

多选题 · hard

  • A.继承 ViewManager 编写← 正确答案
  • B.使用 @ReactProp 暴露属性← 正确答案
  • C.在 ReactPackage 中登记← 正确答案
  • D.修改 Android 系统内核

答案:ABC。完整流程是编写 ViewManager 子类、用 @ReactProp 声明属性、把 ViewManager 加进 ReactPackage 并在应用入口注册。整个过程是应用层开发,无需修改系统内核。

Q9. JSI 与旧 Bridge 的传输本质差异是?

单选题 · mid

  • A.免去 JSON 序列化环节← 正确答案
  • B.改用 XML 数据交换
  • C.强制走 HTTP 协议
  • D.只能单向传送数据

答案:A。JSI 让 JS 直接持有原生对象引用并同步调用,省去 JSON 序列化和异步队列。它不走 HTTP,也不是 XML,更不是单向的——双向同步调用正是它的优势。

Q10. RN 新架构的核心组成包括?

多选题 · hard

  • A.Fabric 渲染器← 正确答案
  • B.TurboModule 模块← 正确答案
  • C.Bridge 批量队列
  • D.持久化虚拟机

答案:AB。RN 新架构(New Architecture)由 Fabric 渲染器和 TurboModule 模块系统两大支柱组成,二者都基于 JSI。Bridge 批量队列是旧架构的产物,持久化虚拟机不是 RN 的组件。