React Native Fabric - Why Am I So Excited?

vishal.chandna   |  19th November, 2018

React has truly changed the way we look at our web apps and with React Native, our vision for native apps is also transforming. It has helped JavaScript to realise its true potential but this is not enough, we still have a long way to go. In this article, we are going to learn about how JavaScript is taking over the Native Apps and how React Native plays a very critical role in achieving it. We are also going to look at a new architecture called Fabric, which is going to be proved as a big enhancement to the React Native architecture.

Current React Native Architecture

The current React Native architecture is very asynchronous and all of the things taking from rendering UI to the JavaScript optimizations are carried out asynchronously. If we look at any native app (developed using the platform-specific language), all the operations are performed synchronously (UI, animations and data manipulations) which makes the app buttery smooth.

How the different operations are carried out in React Native?

There are basically 3 threads in which takes care of all the operations

JavaScript Thread

This is an asynchronous thread which executes our React and JavaScript code. In this, all the DOM hierarchy operations are carried out straight from the code written by the developers. Once the hierarchy is in place, it is sent to the Shadow Thread for optimizations and other necessary operations.

Shadow Thread

This is also an asynchronous thread which acts as our Virtual DOM and executes operations received from the JavaScript Thread. This thread is specifically designed in a way to perform the deep enhancements of the hierarchy. With these enhancements, the redundant operations on user interactions are heavily avoided. Data generated over this thread is sent to the Native Thread over a bridge.

Main Thread

This is our main thread which executes operations synchronously. This is also regarded as the UI thread because at the end all of our component hierarchy is generated in the main thread. All the interactions based on JavaScript is asynchronous so our hierarchy will be out of sync from the UI or frames displayed on any user interaction, animations etc.

Problem with this Architecture?

As we all know, JavaScript works asynchronously so our interactions on the React component’s UI is handled asynchronously. JavaScript thread listens for the user events, scroll events etc. and performs the DOM manipulations accordingly and this whole process is out of sync from the main thread and UI. These are further sent to the Shadow thread for DOM and other refinements which is further sent to the main thread queue. Yoga (a framework) is used to transform the shadow thread response. On the execution of the main thread queue, the changes are reflected on the UI.

So even for a small interaction, it has to traverse all the threads which are in fact not bad but performance wise or especially frames are dropped as the responses cannot be kept synced with the main thread unless these are really synched operations.

It may seem like a small problem but this small problem gives rise to a whole lot more problems e.g Input text interactions are stuttery, animation frames are dropped, long lists are rendered with delays, lag during drag and drop inside the app and a lot more…

Fabric

Fabric is the new React Native architecture proposed by the community to make the mobile application user experience close or even better than the native apps. Just like Fiber architecture in ReactJS has greatly improved the diffing and overall performance, Fabric is to be put in the same direction to improve the performance and efficiency of the app. 

There are basically three main principles of Fabric - 

Prioritizing the Tasks

As we all know JavaScript treats all async events as the same and all of the events/processes are treated equally in terms of resource allocation but with the Fabric architecture, user interactions such as scrolling, touch, hold, gestures etc will be prioritized and will be executed synchronously in the main thread or native thread. While other tasks such as API requests will be executed asynchronously.

Immutable Shadow Tree

As any thread can request a change so this becomes very important for us to have a consistent data or DOM hierarchy. To achieve this, the shadow tree must be immutable. With this, it won’t matter where the changes are coming from as long as our tree is consistent with all other thread that it is being shared with. This is a very important concept which would ensure that there would not be any deadlock condition independent of a synchronous or asynchronous request.

Reducing Memory Consumption

We have seen in the current architecture that we have to maintain two hierarchies/DOM nodes i.e inside Shadow thread and JavaScript thread. This involves a lot of memory consumption, nearly the twice of what it should be. So a new concept is introduced to keep a single copy of it in the memory while the other threads such as JavaScript would only have a reference of it to perform any operations. This concept is very similar to our web applications e.g

let domNode = document.getElementById(‘domNode’);

Where document.getElementById(‘domNode’) returns the native object instead of a JavaScript Object
domNode only keeps a reference to this native object.

How does this new Architecture work?

In the new architecture, there are still three threads but designed in a way to make them as performant and efficient as possible. The first main concept that is used is, now the tasks are divided into sync and async instead of only async. It enables us to perform the important UI operations first and in sync with the frame rate of the mobile screen. In this way, absolute no frame is dropped as the tasks are executed in sync with the user interactions (high priority). Also as any thread can bring out the changes in the Shadow thread (synched with the main thread for priority tasks), it would have to be made immutable to have the consistency and avoid deadlocks.

The other important concept which would greatly reduce the memory consumption is using references instead of a whole new copy of the DOM nodes. This is very helpful in having consistent and efficient DOM nodes. Also with the reference, we can perform any operation that we would have done with its copy but in a much quicker way.

Summary

React Native Fabric architecture is a huge step forward towards innovating the mobile app platforms. Fabric is based on dividing the tasks into sync and async tasks which would be handled by the immutable shadow thread followed by the memory refinements. This architecture makes a lot of sense if we think natively and can truly help us match up with the native applications. I am very excited to see these changes.