启动流程

React Native 启动流程

现在,每当启动 React Native 应用程序时,要加载的第一个项目是本机入口点。Native 线程产生 JS VM 线程,该线程运行捆绑的 JS 代码。JS 代码具有应用程序的所有业务逻辑。JS 基础设施初始化. 主要是 require 等基本模块的加载并替换 JS 默认的实现。自定义 require, Warning window, Alert window, fetch 等都是在这里进行的。基础设施初始化好以后就可以开始加载 js 代码了。

Native 线程现在通过 RN Bridge 发送消息以启动 JS 应用程序。现在,生成的 Javascript 线程开始通过 RN Bridge 向本机线程发出指令。说明包括要加载的视图,要从硬件检索的信息等。例如,如果 JS 线程想要创建视图和文本,它将把请求批处理为单个消息并将其发送到 用于渲染它们的本机线程。

[ [2,3,[2,'Text',{...}]] [2,3,[3,'View',{...

本机线程将执行这些操作并将结果发送回 JS,以确保已执行操作。

image.png

原生代码初始化

这里讨论的主要是 RN 相关的原生代码和用户自定义的 RN 模块的原生代码的加载和初始化。原生代码初始化主要分两步:

  • 静态加载。iOS 没有动态加载原生代码的接口,所有的代码都在编译的初期就已经编译为静态代码并且链接好,程序启动的时候所有的原生代码都会加载好。这是原生代码的静态加载,iOS 里面没有动态加载原生代码的概念,这也是为何没有静态代码热更新的原因。

  • RN 模块解析和注入 JS。这是加载的第二步。在 RootView 初始化的时候会遍历所有被标记为 RCTModule 的原生模块,生成一个 json 格式的模块信息,里面包含模块名称和方法名称,然后注入到 JS Engine, 由 MessageQueue 记录下来。原生代码在生成 json 模块信息的时候同时会在原生代码这边维护一个名称字典,用来把模块和方法的名称映射到原生代码的地址上去,用于 JS 调用原生代码的翻译。

Javascript 环境初始化

RN 的初始化是从 RCRootView 开始的,所有的绘制都会在这个 RootView 里面进行(Alert 除外).RootView 做的第一件事情就是初始化一个空的 JS Engine。这个空的 JS Engine 里面包含一些最基础的模块和方法(fetch, require, alert 等), 没有 UI 绘制模块。RN 的工作就是替换这些基础的模块和方法,然后把 RN 的 UI 绘制模块加载并注入到 JS Engine。JS Engine 不直接管理 UI 的绘制。

  • 所有的绘制由原生控制的 UI 事件和 Timer 触发
  • 影响界面刷新的事件发生以后一部分直接由原生控件消化掉,直接更新原生控件。剩下的部分会通过 Bridge 派发给 MessageQueue,然后在 JS 层进行业务逻辑的计算,再由 React 来进行 Virtual Dom 的管理和更新。Virtual Dom 再通过 MessageQueue 发送重绘指令给对应的原生组件进行 UI 更新。

Native Modules 加载

在 OC 里面,所有 NativeModules 要加载进 JS Engine 都必须遵循一定的协议(protocol)。

模块(OC 里面的类)需要声明为, 然后在类里面还必须调用宏 RCT_EXPORT_MODULE() 用来定义一个接口告诉 JS 当前模块叫什么名字。这个宏可以接受一个可选的参数,指定模块名,不指定的情况下就取类名。

对应的 JS 模块在初始化的时候会调用原生类的[xxx new]方法.

模块声明为后只是告诉 Native Modules 这有一个原生模块,是一个空的模块。要导出任何方法给 JS 使用都必须手动用宏 RCT_EXPORT_METHOD 来导出方法给 JS 用.

所有的原生模块都会注册到 NativeModules 这一个 JS 模块下面去,你如果想要让自己的模块成为一个顶级模块就必须再写一个 JS 文件封装一遍 NativeModules 里面的方法。

你如果想自己的方法导出就默认成为顶级方法,那么你需要一个手动去调用 JSC 的接口,这个在前面章节有讲解。不建议这样做,因为这样你会失去跨 JS 引擎的便利性。

你可以导出常量到 JS 里面去, 模块初始化的时候会坚持用户是否有实现 constantsToExport 方法, 接受一个常量词典。

- (NSDictionary *)constantsToExport
{
  return @{ @"firstDayOfTheWeek": @"Monday" };// JS里面可以直接调用 ModuleName.firstDayOfTheWeek获取这个常量
}

常量只会在初始化的时候调用一次,动态修改该方法的返回值无效

所有标记为 RCT_EXPORT_MODULE 的模块都会在程序启动的时候自动注册好这些模块,主要是记录模块名和方法名。只是注册,不一定会初始化。

懒加载的模块

React Native 的 NativeModules 是有延迟加载机制的。App 初始化的时候

React Native JS 接口兼容(Polyfills) fetch 替换 CommonJS Require alert 替换 console.warning 替换 console.error 替换

上一页
下一页