在 RN 社区的 Upgrade Helper 中能够看到,从 0.67 版别到 0.68 版别的更新中有非常显眼的字眼:

React Native 0.68 includes preview of the New Architecture opt-in.

React Native 新旧架构对比

那么今天咱们就来看下 RN New Architecture 到底新在哪里。

新旧架构比照

开宗明义,咱们先来比照下新旧两个架构图。

旧架构图:

React Native 新旧架构对比

新架构图:

React Native 新旧架构对比

咱们能够显着看到新架构比较旧架构有着以下几点显着不同:

  1. 最左边 JS 层除了 React 之外,还引入了一个静态类型定义 Static Typs
  2. JS 打包成 JS Bundle 这步操作也不再强依赖 JS Core,任何 JS 引擎都能够完结
  3. JS 打包成 JS Bundle 后,不再是简单的经过 JSBridge 与 Native 层进行交互,而是要经过 JSI、Fabric、Turbo Modules 这三个新模块来完结与 Native 层的交互
  4. 在 JS 层和 JSI 之间,还有一个新东西叫 CodeGen
  5. JS 线程 与 用于布局的 Shadow 线程 之间的交互也不再需求经过 Native/UI 线程,直接经过 JSI 就能够完结交互

其中最要害的几个改变如下:

  • JSI(Javascript Interface)
  • Fabric
  • Turbo Modules
  • CodeGen

下面咱们来顺次看下这几个要害改变都带来了哪些重要的改变。

新旧通讯办法比照

旧架构的通讯办法

在旧架构中,JS 与 Native 之间的通讯是经过 JSBridge 来完结的。

React Native 新旧架构对比

当 JS 调用某个 Native 办法(比方敞开蓝牙权限)时,一般会履行以下事项:

  1. JS 线程将事件音讯序列化成 JSON
  2. JS 线程将序列化后的 JSON 信息传递给 JSBridge
  3. JSBridge 将信息传递给 Native 之前,会先将其反序列化
  4. Native 线程接收到反序列化后的信息,并履行对应的 Native 代码

旧的通讯办法存在以下问题:

  1. 一切音讯行列都是异步处理的。虽然大部分情景下异步处理是合理的,可是总避免不了需求同步调用的时分
  2. 音讯传递都需求经过序列化与反序列化,会带来额定的性能开销
  3. 对 Native 的调用是需求进行排队,批处理的

大部分时分Bridge的工作办法没问题,但有时分或许会发生堵塞现象。

比方当页面中有有个翻滚列表,需求翻滚时动态恳求数据并加载,这时分假如用户快速翻滚,或许就会出现白屏。

这是因为 Native 的翻滚事件会经过 JSBridge 传递给 JS 线程,JS 线程再去发送恳求获取下一步烘托数据,然后再将新的烘托数据经过 JSBridge 传递给 Native 线程。这些通讯进程都是异步的,就有或许导致页面空白。

新架构的通讯办法

前面说到的 JSI 支撑起了 RN 新架构的通讯办法。它是一个轻量级的通用层,它是用 C++ 完结的,能够让 JS 引擎直接调用到 Native 端的办法

React Native 新旧架构对比

为什么说它是通用层呢?

旧架构运用的是 JSCore 引擎,而 JSBridge 只能兼容这个特定的引擎。可是关于 JSI 而言,它与引擎彻底解耦,理论上能够在任何 JS 引擎(比方 V8、Hermes)上运用。

JSI 又是怎么让 JS 能够直接调用到 Native 的呢?

Native 办法经过 C++ 宿主目标露出给 JS。经过 JSI 接口,JS 目标能够直接引用 C++ 目标,并调用到它所露出的接口。反之,C++ 目标也能够直接引用并调用 JS 目标的办法。

总而言之,JSI 完结了 JS 目标 与 Native 目标间的同步调用,一起也处理了音讯传递需求序列化和反序列化的问题。

一起 JSI 还有另一大优点,它是用 C++ 编写的,凭借 C++ 的强大功用,在未来 React Native 也能够在其他体系上运转,比方智能电视、智能穿戴设备等等。

新旧烘托器比照

旧架构的烘托器

旧架构的烘托器是 UI Manager,当咱们履行页面烘托时,它是这么运转的:

  1. React 在 JS 侧会依据代码创立一个 ReactElementTree
  2. 烘托器会依据 ReactElementTree 在 C++ 层创立一个 ReactShadowTree
  3. 布局引擎(比方 Yoga)会处理这个 ReactShadowTree 并计算出元素的布局方位
  4. 处理完结后,ShadowTree 会被转换成由 Native 组件构成的 HostViewTree(比方 View 组件会被转换成 Native 的 ViewGroup 组件)

React Native 新旧架构对比

因为旧架构中通讯都是要经过 JSBridge 的,因而旧架构的烘托器也会存在转换慢以及重复数据等问题。一起因为通讯非同步,会存在前面说到的烘托堵塞问题。

新架构的烘托器 —— Fabric

Fabric 是 RN 在新架构中提出的新一代烘托器。

Fabric 凭借了 JSI 的才能,能够做到 JS 线程 和 UI 线程之间的同步通讯。这关于用户体会是有极大的提升的。

比方用户在翻滚列表 / 操作手势时,这些行为都能够同步的反馈给用户,而不再像曾经那样或许会出现堵塞现象。

另外,新的 Shadow Tree 会在 JS 线程 和 UI 线程之间共享,运训来自两端都的直接交互。

新旧 NativeModules 比照

旧架构的 NativeModules

在旧架构中,一切 NativeModules 在 App 启动时都需求被初始化:

  1. 首先 Native 开发者先定义好接口,然后把 NativeModules 注册进一个 Module 列表中
  2. RN 在启动时,会把一切的 Modules 初始化,并生成一份映射表,这份映射表会被注入到 C++ 层和 JS 层
  3. 这样,在 Native 层、C++ 层和 JS 层都存在同一份映射表,JS 能够经过 JSBridge 调用映射表中对应的 Native 办法

旧架构存在一个很显着的问题:即运用户或许永久不会运用到某个 NativeModules,这个 Module 还是会在运用已启动时就被初始化。这有或许会影响到运用的启动时刻

新架构的 NativeModules —— TurboModules

新架构的 NativeModules 叫做 TurboModules:

  1. JS 层首先定义好 Module 的接口(即上面说到的 Static Types),能够用 Typescript 定义
  2. RN 经过 CodeGen 会生成该接口对应的各个平台的 Native 接口,Native 侧只需求继承这个接口去做详细的完结即可
  3. 因为凭借了 JSI 的才能,RN 能够做到只有当 JS 调用到某个 Module 时,才去履行它的初始化,做到真正的模块懒加载

CodeGen

JS 是一种动态类型言语,可是 JSI 是根据 C++ 的, C++ 是一种静态类型言语。

为了确保二者之间能够顺畅的通讯,新架构中引入了静态类型查看器 —— CodeGen。

CodeGen 运用 JS 的类型定义(比方 Typescript)作为声明来源,来生成 Fabric 和 TurboModules 所运用的接口元素。一起 CodeGen 还能够在构建时生成对应的 Native 代码,削减运转时的开销。

总结

RN 新架构比照旧架构有几个要害的改变:

  • 运用 JSI 代替 JSBridge
  • 运用 Fabric 代替 UI Manager,更像 Web 端的烘托体系
  • 运用 TurboModules 代替 NativeModules,支撑 Native 模块懒加载
  • 支撑任何 JS 引擎上运转的潜力
  • 支撑同步通讯
  • 支撑兼容 JS 和 Native 之间的静态类型查看

参考

  • reactnative.dev/docs/next/t…
  • medium.com/coox-tech/d…