React Native 原理与架构深度解析

Viewed 0

React Native 背景介绍

React Native 框架技术源于 Facebook 技术团队,基于其前端框架 React 发展而来,专为开发移动端应用程序而设计。

App 开发的四种模式

移动应用开发主要有四种模式:原生开发、网页应用、混合模式应用以及 React Native。

原生 App 开发使用 Android(Java)和 iOS(Objective-C)的原生框架。这种模式性能与用户体验最佳,动画流畅,交互性好,但需要两套开发与维护团队,成本高,维护复杂,且客户端代码需打包发布,无法动态更新。

网页应用开发 App 即 Web App,通常被称为 H5 应用,在移动浏览器中运行。其开发人员需求少,页面可动态修改,但性能与体验受浏览器限制,流量消耗较大。

Hybrid App 混合模式移动应用介于原生与 Web 之间,拥有原生 App 外壳,内容从云端拉取。开发成本相对较小,页面可随时更新,但性能和体验不及原生,且前期需要原生技术人员搭建外壳。

React Native App 是 Facebook 为改进 Hybrid App 不足而设计的方案。它使用 JSX 编写原生界面,JavaScript 通过 JSBridge 调用原生 API 进行渲染和通信。其设计思路与 Node.js 异曲同工,均通过一个转译桥梁实现不同语言间的通信,使 JavaScript 能够调用移动端原生 API。React Native 开发成本小,只需学习 JavaScript 和 React,效率与体验接近原生,但学习有一定成本,文档相对较少,且不能动态修改页面。与之类似的框架还有阿里的 Weex 和 Google 的 Flutter,但二者社区成熟度相对较低。

JavaScript Core

JavaScript Core 是 React Native 的核心驱动力之一,所有 JavaScript 代码都通过 JavaScript 引擎编译执行,包括 React 的 JSX。除了 JavaScript Core,常见的引擎还有 Google 的 V8 引擎和 Mozilla 的 SpiderMonkey 引擎。

浏览器工作原理与 React Native 对比

在浏览器中,UI 控件调用操作系统绘制指令来绘制图形。React Native 同样使用类 XML 语言描述结构,用 StyleSheet 规划样式,但其 UI 控件调用的是自身的 Android 和 iOS 控件。JavaScript 在 React Native 中的作用是向原生组件发送指令以完成 UI 渲染,因此 JavaScript Core 至关重要。

React Native、React 与 JavaScript Core 的关系

React 是一个纯 JavaScript 框架,依赖 JavaScript 引擎解释执行,并通过 Virtual DOM 实现数据驱动编程和 JSX 语法。但它无法触及操作系统底层,如驱动、线程等。

React Native 的情况更复杂:原生代码驱动 JavaScript 引擎,引擎解析执行 React 及相关代码,然后将计算结果返回给原生代码,最终驱动设备硬件。它利用 Virtual DOM 和数据驱动简化开发,由原生 UI 控件负责绘制,保证了原生体验。由于 JavaScript 无需编译,其运行效率高于基于 HTML5 的 PhoneGap 等技术,后者涉及大量耗时的 DOM 操作。

因此,可以总结为:React Native = JavaScript Core + React.js + Bridges

React Native 架构分析

React Native 的架构可分为三层:

  • Java层:负责 Native 的 UI 渲染和底层功能调用,核心是 react-native.jar,封装了 Module、Registry、Bridge 等接口。
  • C++层:主要封装了 JavaScriptCore,用于解析 JavaScript 代码。
  • JS层:使用 JavaScript 进行事件分发和 UI 编写,包括 Component(用 JSX 构建虚拟 DOM)、Lifecycle(生命周期管理)和 Layout(使用 FlexBox 布局,通过 css-layout 转换为 Native 端代码,目前不支持 CSS3)。

Bridge 通信机制

Bridge 是 JavaScript 与 Native 通信的桥梁,它将本地存储、图片资源访问、图形绘制、网络访问等原生功能封装成 JavaScript 接口并注入 JavaScript 引擎供调用。每个支持 React Native 的原生功能都必须有一个原生模块和一个对应的 JavaScript 模块。

Bridge 原生代码管理原生模块并使其可被 React 调用。JavaScript 与 Native 之间不传递指针,所有参数均通过字符串传递。

Bridge 各模块介绍

  • RCTRootView:React Native 的加载入口,初始化后持有 RCTBridge,加载 JavaScript Bundle 并初始化运行环境,然后启动 UI 绘制。
  • RCTBridge:负责加载和初始化,注册实现了 RCTBridgeModule protocol 的类,并创建持有 RCTBatchedBridge。
  • RCTBatchedBridge:处理 Native 与 JavaScript 之间的相互调用(信息通信)。
  • RCTJavaScriptLoader:实现远程代码加载、热更新和开发环境代码加载。
  • RCTContextExecutor:封装 JavaScript 与 Native 代码的互相调用逻辑。
  • RCTModuleData:加载并管理与 JavaScript 交互的所有原生代码,将其封装成 JavaScript 模块。
  • RCTModuleMethod:记录所有原生导出函数的地址,并生成字符串映射,翻译所有 JavaScript 到 Native 的调用。
  • MessageQueue:负责跳出 JavaScript 引擎,记录原生接口地址和对应的 JavaScript 函数名,在 JavaScript 调用时将其转发给原生接口。

Bridge 如何工作

JavaScript 与 iOS 通信使用 JavaScript Core,与 Android 通信使用 Hermes。

React Native 的线程

React Native 主要包含三个线程:

  1. JS Thread:执行线程,负责逻辑处理。Metro 将 React 源码打包成 bundle 文件,由 JavaScript 引擎执行。
  2. UI Thread:主线程,负责原生 UI 渲染和调用原生能力。
  3. Shadow Thread:创建 Shadow Tree 来模拟 React 结构树,并通过 Yoga 引擎将 Flexbox 布局转换为原生布局。

关键概念:

  • UIManager:在 Native 端唯一有权限调用客户端 UI 的模块。
  • Shadow Node:Native 的组件树,用于监听 UI 变化,类似于虚拟 DOM。
  • Yoga:Facebook 开源的布局引擎,用于转换 Flexbox 布局。

打开 App 时发生什么

以下代码可以用于观察 Bridge 运行过程:

import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue.js'
MessageQueue.spy(true, msg => console.log(msg))

在 App 中加入一个 View 组件:

<View style={{
  backgroundColor: 'green',
  width: 100,
  height: 100
}}/>

流程如下:

  1. 用户点击 App 图标。
  2. UIManager 线程加载所有 Native 库和组件。
  3. Native 侧准备就绪后通知 JS 线程,JS 侧开始加载 bundle 文件。
  4. JavaScript 通过 Bridge 发送 JSON 数据到 Native,描述如何创建 UI。所有 Bridge 通信都是异步的,以避免阻塞 UI。
  5. Shadow 线程最先收到消息,创建 UI 树。
  6. Yoga 引擎计算布局并转换为 Native 布局。
  7. UI Manager 执行操作,展示 Native UI。

Bridge 的缺点与优化原则

Bridge 存在以下缺点:

  • JavaScript 与 Native 处于不同领域,无法相互感知或共享内存。
  • 通信基于异步 Bridge,不能保证数据及时传达。
  • JSON 传输大数据速度慢,且所有传输都是数据复制。
  • 无法同步更新 UI,可能导致列表滚动时卡顿或闪烁。
  • React Native 代码库庞大,修复 Bug 和社区贡献效率相对较慢。

优化 Bridge 缺点的三个原则:

  1. JavaScript 与 Native 避免通信,或直接绕过 Bridge。
  2. 减少通信次数,将多个请求合并。
  3. 减小 JSON 数据的大小。

React Native 新架构

Facebook 团队正在重构 React Native 框架,新架构主要包括:

  1. JSI:将替换 Bridge,是一个用 C++ 编写的 JavaScript 引擎接口。它允许 JavaScript 直接获取 C++ 对象引用并调用方法,实现同步通信,并抹平 JavaScript Core 与 Hermes 的差异。
  2. Fabric:UI Manager 的新名称,负责 Native UI 渲染。它通过 JSI 导出 Native 函数,使 JavaScript 能直接引用和调用,支持同步操作和渲染优先级(如 React 的 Concurrent 和 Suspense 模式)。
  3. CodeGen:将带有静态类型检查的 JavaScript 代码自动转换为 Fabric 和 TurboModules 使用的原生代码,提升性能并减少数据传输出错。
  4. TurboModules:Native 组件的新名称,实现懒加载(而非启动时全部加载),并通过 JSI 导出,使 JavaScript 可以直接引用和同步调用。
  5. Lean Core:旨在减轻 React Native 核心库的负担,让社区更好地解决问题。

新架构下的 App 启动流程

  1. 点击 App 图标。
  2. Fabric 加载 Native 侧。
  3. Native 侧就绪后通知 JS 线程,JS 侧加载所有 bundle 文件。
  4. JavaScript 通过 Native 函数引用调用 Fabric,Shadow Node 创建 UI 树。
  5. Yoga 进行布局计算并转换。
  6. Fabric 执行操作并显示 UI。

新架构通过移除 Bridge 提升了性能,支持同步操作,加快了启动速度,并减小了 App 体积。

0 Answers