React Native新架构特性

512 阅读4分钟

Fabric 的桥接优化详解:传统桥接到 JS 与 C++ 直接交互的演变

在 React Native 的旧架构中,**桥接(Bridge)**是 JS 和 Native 之间通信的核心,但其设计存在一些性能瓶颈。Fabric 新架构中,桥接模式被替代为基于 JSI(JavaScript Interface) 的直接交互,大幅优化了性能和灵活性。


旧桥接机制的局限性

在旧架构中,桥接通过序列化 JSON 数据的方式在 JS 和 Native 之间传递消息。其特点和问题包括:

  1. 通信机制

    • JS 和 Native 运行在不同线程中,通过桥接机制交换数据。

    • 数据通过 JSON 序列化和反序列化后传递。

    • 调用流程:

      1. JS 调用一个 Native 方法。
      2. 数据被打包为 JSON 传递到 Native。
      3. Native 解析 JSON,执行对应逻辑。
  2. 性能瓶颈

    • 高延迟:JSON 的序列化和反序列化耗费大量时间,特别是在高频交互中。
    • 异步通信:即使是简单的 Native 操作,也必须通过异步回调完成,增加了复杂性。
    • 线程切换开销:JS 和 Native 在不同线程间通信频繁切换。
  3. 灵活性不足

    • 缺乏对低级功能的直接访问(如内存、文件系统操作)。
    • 不支持对 Native 对象的引用或操作,导致开发复杂场景时需要额外封装。

Fabric 的桥接优化:JSI + C++ 层直接交互

Fabric 使用 JSI 替代传统桥接,实现了 JS 和 Native 的高效通信。主要改进如下:

1. JSI(JavaScript Interface)的引入

JSI 是一种轻量级的接口,用于直接连接 JavaScript 和 Native。它的特点包括:

  • 无桥接:无需中间桥接层,JS 可以直接调用 Native 对象或函数。
  • 直接内存访问:JS 引擎可以直接操作 C++ 对象,避免序列化和反序列化。
  • 支持同步和异步调用:根据需要选择调用方式,优化性能。
示例:

JSI 提供了一种通过绑定的方式将 Native 方法暴露给 JS:

// 在 Native 层注册一个方法
void install(jsi::Runtime &runtime) {
  auto greet = [](jsi::Runtime &runtime,
                  const jsi::Value &thisValue,
                  const jsi::Value *arguments,
                  size_t count) -> jsi::Value {
    return jsi::String::createFromUtf8(runtime, "Hello from Native!");
  };

  // 将方法绑定到全局对象
  runtime.global().setProperty(
      runtime, "greet", jsi::Function::createFromHostFunction(
                            runtime, jsi::PropNameID::forAscii(runtime, "greet"),
                            0, greet));
}

在 JS 层可以直接调用:

console.log(global.greet()); // 输出: Hello from Native!

2. Native 对象的直接暴露

Fabric 中,Native 对象可以通过 C++ 的引用直接暴露给 JS:

  • 无需序列化:Native 对象可以直接暴露给 JS,而不需要转换为 JSON。
  • 对象持久化:JS 可以持有 C++ 对象的引用,避免重复创建。
示例:

暴露一个 Native 对象给 JS:

class Counter {
  int value_;

public:
  Counter() : value_(0) {}

  void increment() { value_++; }
  int getValue() const { return value_; }
};

void installCounter(jsi::Runtime &runtime) {
  auto counter = std::make_shared<Counter>();
  runtime.global().setProperty(
      runtime, "counter",
      jsi::Object::createFromHostObject(runtime, counter));
}

在 JS 中直接操作该对象:

global.counter.increment();
console.log(global.counter.getValue()); // 输出: 1

3. 性能提升

Fabric 的桥接优化显著降低了性能开销:

  • 无序列化成本:通过 JSI,JS 和 Native 层共享对象,避免 JSON 的解析和打包。
  • 低延迟同步调用:JSI 支持同步调用,使得高频操作(如动画、手势)更流畅。
  • 线程切换优化:JS 和 Native 的直接交互减少了线程切换次数。
对比示例:

旧架构:

NativeModules.MyModule.doSomething({ key: "value" }, (result) => {
  console.log(result);
});

Fabric 架构:

const result = global.MyNativeFunction({ key: "value" });
console.log(result);

4. 模块加载优化:TurboModules

Fabric 中结合 JSI 和 TurboModules,进一步优化了模块加载和通信:

  • 按需加载:只有在需要时才加载模块,减少启动时间。
  • 模块静态绑定:模块定义在 C++ 层,并通过 JSI 自动绑定到 JS。
示例:

定义一个 TurboModule:

class MyModule : public facebook::react::TurboModule {
public:
  MyModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker)
      : TurboModule("MyModule", jsInvoker) {}

  jsi::Value myMethod(jsi::Runtime &runtime, const jsi::Value *args, size_t count) {
    return jsi::String::createFromUtf8(runtime, "Hello TurboModule!");
  }
};

桥接优化的优势

  1. 性能

    • 减少通信开销。
    • 更高效的高频操作支持(如动画、实时数据流)。
  2. 灵活性

    • 直接访问 Native 功能(如文件系统、内存)。
    • 更易于扩展和集成第三方库。
  3. 一致性

    • Fabric 的设计在 iOS 和 Android 上保持一致的实现,减少跨平台差异。

总结

Fabric 新架构通过 JSI 和 C++ 直接交互的方式,彻底消除了旧桥接的性能瓶颈。通过这种优化,React Native 的 JS 和 Native 层能够实现低延迟、高效和灵活的通信,这为复杂的 UI 渲染、高性能应用程序以及未来的扩展提供了坚实基础。