-
概览\
-
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方法\
- TurboModule类继承自HostObject,这样js就可以持有TurboModule对象
- 利用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 类名,然后创建实例化对象\
- 通常由codegen生成一份配置表,键值对格式,key 是 module名,value是原生类包,配置表的结构可参考下面的系统核心模块
-
接口一致性保障\
- 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这样的方法
\
- 在创建JSExecutorFactory前,创建了TurboModuleManager对象,并把bridge与TurboModuleManager对象做了绑定
-
-
TurboModuleBinding创建\
-
创建JSExecutorFactory\
- 执行js代码的抽象类,其子类如JSCExecutorFactory使用jsc引擎,HermesExecutorFactory使用Hermes引擎\
- bridge初始化的最后阶段,执行闭包RCTJSIExecutorRuntimeInstaller
\
-
执行TurboModuleManager.installJSBindingWithRuntimeExecutor方法\
-
创建闭包turboModuleProvider\
- 它是__turboModuleProxy桥接中的c++侧的实现方法\
- turboModuleProvider内部将根据module name返回module实例\
-
执行TurboModuleBinding.install方法\
- 建立c++与js的桥接
\
- 建立c++与js的桥接
-
-
建立__turboModuleProxy桥接\
- 往js侧全局global添加一个名叫__turboModuleProxy的方法
\
- jsProxy方法其实是调用前面创建的turboModuleProvider block,根据module name 查找/创建turbo module
\
- moduleProvider_是在install方法中作为参数传进来的,install方法中实例化了TurboModuleBinding对象,入参便是moduleProvider,所以最终执行的是前面创建的闭包turboModuleProvider
\
- 往js侧全局global添加一个名叫__turboModuleProxy的方法
-
-
js侧调用trubomoudule\
- 以官方demo为例,当外层import此模块时,调用TurboModuleRegistry.get方法
\
- 最终会调用__turboModuleProxy桥接,通过name查找到对应的原生模块
\
- 以官方demo为例,当外层import此模块时,调用TurboModuleRegistry.get方法
-
c++侧获取turbomodule实例\
- __turboModuleProxy桥接被触发时,c++侧会执行预先定义的moduleProvider方法
\
- jsProxy方法根据传入的name查找对应的turbomodule\
- jsProxy内部又调用了其它方法,最终走到了provideTurboModule\
- __turboModuleProxy桥接被触发时,c++侧会执行预先定义的moduleProvider方法
-
provideTurboModule根据name获取turbo module\
- 主要有三步
\
- 首先查找缓存,之前创建过该turbomodule对象,则直接返回\
- 第二步优先创建c++ module\
- 第三步创建平台指定的module\
- 主要有三步
-
TurboModule\
- TurboModule是HostObject的子类,HostObject 是从 C/C++ 向 JavaScript 映射过去的对象。所以js也能访问/操作TurboModule
\
- TurboModule是HostObject的子类,HostObject 是从 C/C++ 向 JavaScript 映射过去的对象。所以js也能访问/操作TurboModule
-
-
参考资料\