RN新架构-Turbo原理

1,079 阅读4分钟
  • 概览\

    • turbo Module是 Native Module 的升级版\

      • turbo是涡轮的意思,Native Module能够让js调用Native的Module/原生api,turbo Module是对 Native Module 的全面升级,以加快从 JavaScript 初始化和调用原生模块的方式。\
    • 现有架构Native Module存在的问题\

      • 初始化速度,由于不支持惰加载,app启动时加载全部Native Module,启动时间过长\
      • 接口一致性,Native Module 所提供的接口,在 Native 侧和 JavaScript 侧各有一份,两者必须严格一致。但一致依赖缺少保障机制\
      • 单例,Native Module 采用单例设计,生命周期过长\
      • 多余的运行时操作,Native Modules的方法列表是在运行时进行扫描,完全可以放到编译期\
      • 反射,Native Module 中的方法通过运行时反射调用。这个反射可以被优化。\
    • 新旧方式对比\

      • \
  • 实现原理\

    • Turbo Module 建立在 JSI 机制之上。\

      • RN引擎初始化时,往js侧全局global添加一个名叫__turboModuleProxy的桥接方法\

        • js侧通过这个桥接方法调用原生侧的turbo module,js侧传入module name,原生返回一个HostObject类型的对象\
        • 原生侧根据接收到的module name查找/创建trubo module\
      • Turbo Module其实是JSI中的HostObject\

        • TurboModule类继承自HostObject,这样js就可以持有TurboModule对象\
        • TurboModule有两个子类ObjCTurboModule和JavaTurboModule,分别用于ios和安卓\
        • js侧每次调用HostObject的方法,最终会进入TurboModule的get方法\
      • 利用jsi机制建立js层与c++层的通道,js层传入module name,获取在c++层注册的trubo module,并调用该module暴露的api(方法和属性)\
    • Turbo Module 懒加载实现\

      • 当js侧调用turbo module时,通过桥接方法,向原生端传递要调用的module name\
      • 原生侧收到桥方法时,创建该turbo module实例\

        • 首先读取本地缓存,命中则返回该turbo module实例\
        • 未命中则尝试创建c++ module实例\
        • 创建失败则创建JavaTurboModule/ObjcModule实例\
        • 以上过程中,创建成功将实例写入缓存\
      • 创建turbo module实例的过程\

        • 通常由codegen生成一份配置表,键值对格式,key 是 module名,value是原生类包,配置表的结构可参考下面的系统核心模块\
        • 从配置表中读取module 类名,然后创建实例化对象\
    • 接口一致性保障\

      • Turbo Module通过JS侧的接口生成C++中间层的JSI代码,并且生成对应的OC/Java的接口。然后基于接口来实现Native方法,从而达到了JS - Native两侧的接口一致性\
      • CodeGen是一个开发工具,作用是静态类型检查器(Flow或TypeScript),目的是以自动化的形式来保证JS侧与Native侧的兼容性。用来解决之前检查JS侧接口与Native侧接口一致性比较困难的问题\
  • 源码分析\

    • TurboModuleManager对象创建\

      • 创建bridge\

        • 打开RN页面前,首先创建一个rn bridge,bridge内部持有了batchBridge对象,bridge初始化时,调用了batchBridge的start方法\
        • 启用TurboModule时,需要开发者实现RCTCxxBridgeDelegate协议,所以这里会调用jsExectorFactoryForBridge方法\

          • RCTCxxBridgeDelegate协议的jsExecutorFactoryForBridge方法,可以指定js引擎,如Hermes引擎或jsc引擎,如果未实现,默认使用jsc引擎\
      • 创建TurboModuleManager\

        • 在创建JSExecutorFactory前,创建了TurboModuleManager对象,并把bridge与TurboModuleManager对象做了绑定\
        • TurboModuleManager实现了RCTTurboModuleRegistry协议,故名思义,它的作用是管理项目中的turbo module的注册和查询\
        • RCTTurboModuleRegistry协议允许管理其它的TurboModule,提供了moduleForName、moduleIsInitialized这样的方法\
    • TurboModuleBinding创建\

      • 创建JSExecutorFactory\

        • 执行js代码的抽象类,其子类如JSCExecutorFactory使用jsc引擎,HermesExecutorFactory使用Hermes引擎\
        • bridge初始化的最后阶段,执行闭包RCTJSIExecutorRuntimeInstaller\
      • 执行TurboModuleManager.installJSBindingWithRuntimeExecutor方法\

        • 创建闭包turboModuleProvider\

          • 它是__turboModuleProxy桥接中的c++侧的实现方法\
          • turboModuleProvider内部将根据module name返回module实例\
        • 执行TurboModuleBinding.install方法\

          • 建立c++与js的桥接\
      • 建立__turboModuleProxy桥接\

        • 往js侧全局global添加一个名叫__turboModuleProxy的方法\
        • jsProxy方法其实是调用前面创建的turboModuleProvider block,根据module name 查找/创建turbo module\
        • moduleProvider_是在install方法中作为参数传进来的,install方法中实例化了TurboModuleBinding对象,入参便是moduleProvider,所以最终执行的是前面创建的闭包turboModuleProvider\
    • js侧调用trubomoudule\

      • 以官方demo为例,当外层import此模块时,调用TurboModuleRegistry.get方法\
      • 最终会调用__turboModuleProxy桥接,通过name查找到对应的原生模块\
    • c++侧获取turbomodule实例\

      • __turboModuleProxy桥接被触发时,c++侧会执行预先定义的moduleProvider方法\
      • jsProxy方法根据传入的name查找对应的turbomodule\
      • jsProxy内部又调用了其它方法,最终走到了provideTurboModule\
    • provideTurboModule根据name获取turbo module\

      • 主要有三步\
      • 首先查找缓存,之前创建过该turbomodule对象,则直接返回\
      • 第二步优先创建c++ module\
      • 第三步创建平台指定的module\
    • TurboModule\

      • TurboModule是HostObject的子类,HostObject 是从 C/C++ 向 JavaScript 映射过去的对象。所以js也能访问/操作TurboModule\
  • 参考资料\