浅谈 react native 的新旧架构

112 阅读6分钟

前言

时至今日,react native 的版本号已经垒到了 0.79。虽然离我们渴望的第一个大版本似乎还遥遥无期,但是值得欣慰的是,它在 0.76 版本实现了新架构,使得 react native 应用在性能上有了质的飞跃。这无疑是 react native 的 iPhone 时刻。

也许你会问,为什么要了解架构层面上的东西呢?我觉得对架构层面上的东西进行了解,有助于开发者在理解运行原理上塑造一个正确的心智模型。有了这个心智模型,才能为后面的性能优化,高效 debug,编写 scalable 和高质量代码编写提供坚实的基础。

正文

旧架构:bridge 模式

在旧架构中,React Native 存在两个独立的世界:

  • JavaScript 世界 — 应用程序逻辑运行的地方
  • native 世界 — UI和系统功能工作的地方

由于这两个世界使用不同的语言(JavaScript与Swift/Java/Kotlin),他们需要一种通信方式。这就是 bridge 当初被设计出来的理由。

bridge 模式的工作原理

  1. JavaScript侧通过 bridge 发送 JSON 消息,告诉 native 侧该怎么做;
  2. native 侧读取这些消息,并执行它们(例如,渲染按钮,更新文本);
  3. 如果用户与UI进行交互(例如敲击按钮),则native 侧通过 bridge 将消息发送回 JavaScript。
sequenceDiagram
    participant JS as JavaScript
    participant Bridge
    participant Native

    JS->>Bridge: Send JSON Message (e.g., Render Button)
    activate Bridge
    Bridge->>Native: Deliver Message
    deactivate Bridge
    activate Native
    Native->>Native: Execute Message (Render Button)
    Native->>Native: User Interaction (e.g., Tap Button)
    Native->>Bridge: Send Message (User Action)
    deactivate Native
    activate Bridge
    Bridge->>JS: Deliver Message
    deactivate Bridge
    JS->>JS: Process Message (Update UI)

举个例子:如果您需要用 input 输入框和按钮来创建一个 react native 登录页面:

  1. JavaScript通过 bridge 发送消息:
  • “使用这些样式创建输入框”
  • “使用这些属性创建一个按钮”
  1. native 侧收到消息并呈现 UI。
  2. 当用户输入文本时,native 侧将数据通过 bridge 发送回JavaScript。

旧架构中的 React Native 中的线程

React Native 应用程序在多个线程上运行:

  • JavaScript 线程 - 执行所有React Native逻辑并发起UI更新请求。
  • Native 线程 - 为UI元素运行特定于平台的代码(Swift、Java/Kotlin)。
  • Shadow 线程 - 使用 Yoga 引擎处理布局(将CSS样式转换为原生布局)。

旧架构的缺点

1.性能问题

因为消息是通过 bridage 异步传递过来的,所以,JavaScript和 Native之间的通信速度很慢,通讯效率低。 如果 UI 更新不及时,在用户快速地滚动列表的时候就会出现卡顿现象。

2.没有共享内存

JavaScript和 Native不共享内存。 同一份数据,React Native 以JSON格式复制它,并在 JavaScript和Native 侧的内存各开辟两个内存块去存储,数据冗余度高且浪费计算资源。

3.native 模块加载冗余

即使有些模块在应用的运行时并不需要, React Native 也会在启动时加载所有 native 模块,这无疑不必要地增加了应用的启动时间

4.难以贡献源码

React Native代码库很复杂,开发人员很难贡献代码去修复问题或优化代码。

新架构:Fabric & Turbo Modules

为了解决这些问题,React Native 引入了一种包含Fabric 和 TurboModules的新架构。

什么是 Fabric ?

Fabric 移除了 Bridge,并在 JavaScript 和 Native之间引入了更快、更高效的通信模型。

为什么 Fabric 更好?

  • 使用同步通信(而不是像以前那样使用异步消息)。
  • 允许JavaScript和 Native 共享内存,减少复制数据的需要。
  • 提高UI响应速度和流畅性。

什么是 Turbo Modules?

Turbo Modules 允许 React Native只加载应用所需的native 模块,而不是在启动时一股脑加载所有。

为什么 Turbo Modules 更好?

  • 缩短应用程序启动时间。
  • 通过按需加载模块来节省内存。

新旧架构对比

当你点击 React Native 应用程序图标时会发生什么?

让我们一步一步地看看!

步骤1:应用程序启动和UI管理器启动

当你点击 app 在系统桌面的图标时,操作系统会启动应用程序并加载React Native。

UI manager 初始化所有 native 组件,如文本输入框、按钮、图像等。

步骤2: 加载 JavaScript bundler 文件

React Native加载 MainBundle.js,其中包含应用程序的所有 JavaScript 代码。 如果你在应用程序启动时检查终端,你会看到显示“Loading MainBundle.js”的日志。

步骤3:通过 bridge(旧架构)或 Fabric(新架构)创建视图

旧架构:JavaScript向 Bridge 发送JSON消息以创建UI元素。 新架构:Fabric直接与 native 代码交互,使 UI 渲染更快。

步骤4:布局计算(使用Yoga引擎)

React Native不像 web 那样使用标准 CSS。 相反,它使用 Yoga 引擎来「计算」元素的布局和位置。 布局计算发生在 shadow 线程。

步骤5:UI出现在屏幕上

最后,UI manager 根据计算出的布局显示 UI。你可以看到该应用程序已完全加载并处于可交互状态!🎉

MainBundle.js

在 React Native应用程序中,MainBundle.js(或Android上的index.bundle.js)是包含整个应用程序JavaScript 代码的 JavaScript bundle。

它里面有什么?

它是在构建应用程序时生成的,包括下面四部分:

  • 所有开发者编写的 JavaScript代码和引用的第三方 npm 包的源码 — 整个React Native应用程序逻辑。
  • React和 React Native 核心API — 渲染所需的基本库。
  • Metro 打包器 ship 进来的,用于优化和 polyfill 的 JavaScript 代码。
  • native 调用 bridge 的代码(如果使用旧架构)— 与native 组件通信的代码。

它如何产生?

当你执行下面命令的时候:

Metro Bundle

Metro Bundle 就是 react native 中的 webpack。它的职责跟常规的 js 应用打包器是一样的:

  • 将ES6+JavaScript编译成兼容的ES5语法。
  • 将多个JavaScript文件合并到一个包中。
  • 代码压缩(用于生产)。
  • 处理开发过程中的 hot reload。

新旧架构类比

对旧架构的简单类比

把 React Native 应用程序想象成一个餐厅,它的运行就好比在餐馆点餐的流程:

  • JavaScript线程(客户)— 决定点什么食物(逻辑)。
  • Bridge(服务员)— 将订单传递到厨房(native 侧)。
  • native 侧(厨房)——准备食物(渲染UI)。
  • UI manager(服务员)——将食物带到你的桌子上(显示UI)。

如果餐厅业务太忙(bridge 接收到请求太多),服务就会变慢。这就是为什么新版本的 React Native(Fabric和TurboModules)减少了对 Bridge 的依赖,以获得更好的性能。

对新架构的简单类比

  • JavaScript线程(客户)— 决定客户想要什么(应用程序逻辑)。
  • Fabric(厨房)— 准备食物(UI渲染)。
  • TurboModules(高级厨房工具)— 处理专门的烹饪(访问相机或GPS等本地功能)。
  • 直接沟通(服务员)— 直接送餐,没有任何不必要的延误。

小结

一句话总结,相比于旧架构, react native 的新架构会更直接和高效,故,性能上的表现会更优异。

资料

意译: React Native Architecture: A Deep Dive into the Old vs. New Approaches | by Sulegjan Sasikumar | Medium