Some time ago, I did a technical sharing of “ReactNative principle analysis” in the company. Due to the lack of detailed PPT, I sorted out a series of articles on ReactNative principle analysis to meet the needs of some partners, hoping that we could have a systematic and comprehensive understanding of the underlying principle of ReactNative.

  • “ReactNative Principle” startup process
  • “ReactNative principle” JS layer rendering diff algorithm
  • “ReactNative Principle” Native layer rendering process

Before you read this article, consider this question:

Why can ReactNative achieve cross-end and hot update as well as the Web, but with nearly Native performance?

The essence of ReactNativeThe React code is written on the JS side, and the components and events written on the JS side are converted into Native components for rendering through the JavaScriptCore engine, as shown in the following figure:

To understand the implementation principle of ReactNative, it is mainly to understand the communication principle between JS end and Native end. In order to ensure that JavaScript and Native have the ability to communicate with each other, first of all, it is necessary to figure out what RN does when it starts up. This article is based on the analysis of ReactNatve source code to analyze the startup process of ReactNative in a simple way.

An overview of the

What is the entry point for ReactNative startup?

  • ReactNative starts by creating a RCTRootView as an entry view container. When RCTRootView is created, a JSBridge is created as a bridge between the Native end and the JS end. The startup of the entire RN is basically done when JSBridge is created.

  • The core of JSBridge is RCTBatchedBridge, the work of JSBridge is mainly handled in the initialization of RCTBatchedBridge. Start the process using the GCD for multithreaded operations, the most time-consuming operation is in the concurrent queue com. Facebook. React. RCTBridgeQueue.

  • RCTBatchedBridge will be launched with six preparations:

1. Load JSBundle code (parallel queue execution asynchronously)

2. Initialize Native Modules (synchronous execution)

3. Initialize JSCExecutor (on the same parallel queue as step 4)

4. Create the Module configuration table (on the same parallel queue as step 3)

5. Inject Module configuration information into JSCExecutor (steps 3 and 4)

6. Execute JSBundle code (execute the first 5 steps)

To put it simply, JSBridge initialization is the preparation from loading the JS source code (JSBundle) to the JSBundle being able to be executed natively. First, ReactNative JS components and events eventually map to Native components, and all Native components expose JavaScript classes in Native Modules. So how does the JS side map to a native component? Find the corresponding class in Native Modules through the Module configuration table. Finally, interactions such as JS calls to native methods, and mapping to native code, are through JSCExecutor.

Therefore, the initialization of JSBridge, namely, the initialization of JSBundle, Native Modules, Module configuration table, and JSCExecutor, is as follows:

1. Load the JSBundle code

JSBundle: Resource files such as JavaScript source code and images generated after the React code is packaged

The essence of hot updates: Put the JSBundle on the server, download the JSBundle locally to implement hot updates when appropriate (before startup/switching background/opening a page to load on demand, etc.)

Load the JavaScript source code into memory for later injection and execution. In this step, the JSX syntax in React has been converted to JavaScript. The execution code is as follows:

[RCTBatchedBridge loadSource: onProgress:]
Copy the code

2. Initialize Native Modules

Synchronously initializes all Native modules called by the JS side that cannot be lazily loaded.

Native Modules: All classes Native needs to expose to JS (i.e., classes marked with macro: RCT_EXPORT_MODULE())

Main purpose: Find all Native classes that need to be exposed to JavaScript (i.e., classes marked with macro: RCT_EXPORT_MODULE()), so that these module information can be injected into the JS side later. The execution code is as follows:

[RCTBatchedBridge initModulesWithDispatchGroup:]
Copy the code

3. Initialize JSCExecutor

JSCExecutor is a JavaScriptCore engine responsible for communication between the JS side and the Native side

The execution code is as follows:

[RCTBatchedBridge setUpExecutor]
Copy the code

1. During initialization, create a separate JS thread with the same priority as the main thread, and create a Runloop so that the JS thread can execute in a loop without exiting.

2. During initialization, JavaScriptCore is used as the engine to create the CONTEXT for JS execution and inject the communication method between JS and Native into the JS context. Among them, several important methods for JS side invocation implemented in Native side are as follows:

  • NativeRequireModuleConfig: js for native module configuration tables. RN does not save the entire Native method configuration table, only the module name. This callback allows JS to check the module configuration information based on the module name each time

  • NativeFlushQueueImmediate: js trigger native queue the message processing. Generally speaking, JS will not actively call Native methods, but wait for Native timer to fetch from JS eventQueue at intervals, and execute in batches after it is retrieved. While nativeFlushQueueImmediate directly call the Native method is to make the JS without waiting.

  • NativeCallSyncHook: Synchronous call

4. Create the Module configuration table

Module configuration table:

1. Collect all module information, save it in an array, and inject it into JS after serialization.

2, JS end by Native end injection nativeRequireModuleConfig method, according to the module name can query the module configuration information.

Create the Module configuration table, with initialization JSCExecutor operation was to join the concurrent queue com. Facebook. React. RCTBridgeQueue asynchronous. The execution code is as follows:

[RCTBatchedBridge moduleConfig]
Copy the code
- (NSString *)moduleConfig
{
  NSMutableArray<NSArray* >*config = [NSMutableArray new];
  for (RCTModuleData *moduleData in _moduleDataByID) {
    if (self.executorClass = = [RCTJSCExecutor class]) {
      [config addObject:@[moduleData.name]];
    } else {
      [config addObject:RCTNullIfNil(moduleData.config)]; }}return RCTJSONStringify(@{
    @"remoteModuleConfig": config,
  }, NULL);
}
Copy the code

When obtaining moduleConfig, module information will be collected differently depending on the executorClass. For RCTJSCExecutor, Native saves only the module name. JS end by Native end injection nativeRequireModuleConfig method, according to the module name can find this module module configuration information. If the module type is not RCTJSCExecutor, the moduleData.config link to [RCTModuleData config] will save the configuration information of native Modules, such as module names, constants, and functions.

5. Inject Module configuration information into the JS side

Perform [RCTBatchedBridge injectJSONConfiguration:onComplete:]
Copy the code

When the JSCExecutor is initialized and the Module configuration table is created, the Module configuration information is injected into the JS side.

6. Execute JSBundle code

Perform [RCTBatchedBridge executeSourceCode:]
Copy the code

After the above five steps are complete, execute the JavaScript source code in the JSBundle. At this point, JavaScript and Objective-C have the ability to interact with each other, and the preparation for starting the process is complete.

After startup, it will enter the rendering layer, which is divided into JS layer and native part:

  • “ReactNative principle” JS layer rendering diff algorithm
  • “ReactNative Principle” Native layer rendering process

conclusion

If you are also a programmer interested in investment and financial management, welcome to pay attention to my public account “flying dragon at the bottom of the valley”, and become the investment leader of the technology industry.


You think it’s nice give me a small onepraiseEncouragement ~