background
With the rise of Flutter and other new frameworks, React Native is facing more and more challenges, and RN’s performance bottleneck is becoming more and more obvious. In order to remain competitive against frameworks like Flutter, RN is considering a very big upgrade in architecture. In a ReactConf 2018 talk React Native’s New Architecture, the RN introduces three New concepts: JSI, Fabric, and TurboModule. Then in the first quarter of 2019, RN developers @ kelset wrote an article explain why an RN so architecture from the high-level design article: formidable.com/blog/2019/j… . Let’s take a look at how RN solves the performance bottleneck.
Existing problems
RN’s older architecture relied heavily on Bridge:
All information transmitted between JS and Native should be serialized to JSON for asynchronous transmission. This leads to a fairly common performance problem: a blank screen when scrolling through the ListView quickly, as shown below:
There are now three threads: the Native UI thread, the Layout thread, and the JS thread, and the communication between them is asynchronous. When the ListView slides up and needs to display a new Cell, Native sends an asynchronous notification to the JS thread. After the JS thread performs the corresponding business logic processing, it sends an asynchronous notification to the Layout thread to calculate the actual display area of the Cell. After that, the Layout thread will asynchronously send the calculated results to the Native thread for UI drawing. As the sliding speed is very fast, the UI can not be updated in time and the blank screen will be displayed.
To solve this problem, let’s take a look at how ListView does not have a blank screen in the browser.
In the node returned by the browser, there is a reference to the object actually generated by C++, so JS calls to the browser are synchronous calls, naturally there will be no blank screen problem.
In the same way, if we remove the asynchronous bridge, JS and Native hold a HostObject at the same time, then synchronous calls between JS and Native can be made. This leads to a replacement for Bridge, JavaScript Interface (JSI).
JavaScript Interface (JSI)
JSI is a streamlined, general-purpose JS engine interface that can theoretically connect to any JS engine, including Google’s V8 and Microsoft’s ChakraCore, or a newer version of JavaScriptCore (JSC) that RN now uses (JSI has been integrated into VERSION 0.59 of RN). And upgraded the JSC version in this release).
At the same time, JSI is a bridge between JS and Native. By implementing a JSI::HostObject in C++ layer, the direct communication between Native and JS is realized without serialization into JSON and two-way transmission.
ListView sliding under JSI
The dashed line is an asynchronous invocation, and the implementation is a synchronous invocation.
First we RunApplication, then asynchronize render, and then asynchronize the UI thread to update the View. Before JSI came along, this was the only way we could handle Native interaction with JS.
Now the UI thread has a callback for a network request to update state, followed by a list of onScroll events in the UI thread, and obviously, this onScroll event is the task we need to deal with urgently. With JSI, we can handle the onScroll task synchronously and update the corresponding Native View, so that the problem of blank screen will not appear. After handling this urgent task, the main thread can continue to handle the network request callback.
Native Modules in JSI
JSI is also the cornerstone of Native Modules remodeling (TurboModules). Let’s say I have a requirement to take a picture in RN and upload it to the server. Before THE advent of JSI, we needed to repeatedly serialize between JS and Native to pass data, which was inefficient and unnecessary:
After having JSI, JS and Native hold a HostObject at the same time. After obtaining the image, they will skip unnecessary data transmission and directly continue to complete the uploading operation.
Reference
React Native’s New Architecture
Formidable.com/blog/2019/j…