阅读 423

React Native 实现原理、渲染、通信机制总结

整体架构、流程

  1. 首先写好JSX代码(React框架就是使用JSX语法)

  2. 把JSX代码解析成javaScript代码

  3. OC读取JS文件

  4. 把javaScript代码读取出来,利用JavaScriptCore执行

  5. javaScript代码返回一个数组,数组中会描述OC对象,OC对象的属性,OC对象所需要执行的方法,这样就能让这个对象设置属性,并且调用方法。


  • 如果你了解这些东西的本质其实就很清楚了。动态或者脚本语言要跟本地语言互通要具备如下几点:

    1. 本地语言有一个runtime机制来对对象的方法调用进行动态解析。

    2. 本地语言一定有一个脚本的解析引擎

    3. 建立一个脚本语言到本地语言的映射表,KEY是脚本语言认识的符号,VALUE是本地语言认识的符号。通过这个映射表来构建从脚本到本地的调用。

  • 通过上述3个原则,无论是RN, JSPATCH, WEEKS, WEX都是使用同样的机制。。没有什么神秘可言,也没有什么复杂度可言了。。。

启动流程

React Native启动流程(iOS)

React Native加载JS源码流程(iOS)

渲染原理

现场模型

通信机制

ReactNative 的初始化

native module 注册

  • 要将 Native module(类、接口)曝露给 JS,module需要实现RCTBridgeModule协议,并且在实现中要插入RCT_EXPORT_MODULE宏。具体曝露的方法也需要通过RCT_EXPORT_METHOD宏定义。

  • RCT_EXPORT_MODULE的源码:

    RCT_EXTERN void RCTRegisterModule(Class);    +(NSString *)moduleName                      {                                              return @ #js_name;                         }                                            +(void)load                                  {                                              RCTRegisterModule(self);                   } 复制代码

  • 通过上图流程,native module注册最终定位到RCTCxxBridge._initModulesWithDispatchGroup

    - (void)_initModulesWithDispatchGroup:(dispatch_group_t)dispatchGroup {     NSMutableArray<Class> *moduleClassesByID = [NSMutableArray new];     NSMutableArray<RCTModuleData *> *moduleDataByID = [NSMutableArray new];     NSMutableDictionary<NSString *, RCTModuleData *> *moduleDataByName = [NSMutableDictionary new];     // Set up moduleData for automatically-exported modules     for (Class moduleClass in RCTGetModuleClasses()) {         NSString *moduleName = RCTBridgeModuleNameForClass(moduleClass);         moduleData = [[RCTModuleData alloc] initWithModuleClass:moduleClass bridge:self];         moduleDataByName[moduleName] = moduleData;         [moduleClassesByID addObject:moduleClass];         [moduleDataByID addObject:moduleData];            }     // Store modules     _moduleDataByID = [moduleDataByID copy];     _moduleDataByName = [moduleDataByName copy];     _moduleClassesByID = [moduleClassesByID copy]; } 复制代码

  • 上述代码第8RCTGetModuleClasses()即是获取通过RCTRegisterModule注册的 module 类(即所有曝露给 JS 的类)

  • 至此,所有需要曝露给 JS 的 module 都已注册完成,并以RCTModuleData格式存储在RCTCxxBridge中。

  • 大部分 module 都是懒加载,只有那些需要在主线程完成初始化以及有常量需要导出的 module才会在注册时实例化。

JS 获取 native module 信息

  • 收集了所有曝露给 JS 的 module(也可称之为生成了一份 native module 注册表);

  • 在 JS Context 中设置了nativeModuleProxy以及nativeFlushQueueImmediate

  • 初始化了相关的类,如:NativeToJsBridgeJsToNativeBridge以及JSCExecutor

JS 调用 native module

  • NativeModules.moduleName — 该过程主要是获取 native module 的信息(moduleID、methodID),最终封装为 JS object ({methodName: fn});

  • NativeModules.moduleName.methodName(params) — 执行调用。

总结

  • RN 项目中涉及多种语言,但 Native 与 JS 的通信发生在C++JavaScript间;

  • 双方具体负责通信的分别是:Native 的JSCExecutor与 JS 的MessageQueue

  • 在 Native 侧维护了一份曝露给 JS 的 module 注册表,在 JS 侧维护了一份曝露给 Native 的 module 注册表;

  • RN 中 Native to JS 的通信没有使用JavaScriptCore提供的机制(blockJSExport),而是自己实现了一套跨平台通信机制。


作者:逍遥归来
链接:https://juejin.cn/post/7018847318371729415


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐