Best Practices

How JavaScript works. Learn best practices, find the node that is taking time to render, improve FPS performance, learn when to do image caching and find out about Hermes.

Best practices#

My Mantra is: Everything ties down to freeing up the Javascript thread.

We have come across a lot of best practices in the course so far, and adapting these has definitely helped to build a performant app.

However, our app can still face performance bottlenecks, such as when trying to render a very long list, display a lot of images, or for other reasons, which we may need to troubleshoot.

Let's look at what we can do in such scenarios.

The official performance guide from React Native is a goldmine for troubleshooting issues, and you should be familiar with these. Here we will discuss what I have found to be the commonest issues, with useful suggestions.

How JavaScript works#

JavaScript is a single-threaded language. What that means is it has only a single thread to do whatever we want it to do. It has event loops and all the code must be executed or resolved in the same event loop, or the application will have to drop frames to accommodate for the extra time taken.

How JavaScript works

From the UI perspective: In the above picture, if the console.log('Third') command takes more than 16ms, the app will have to drop one frame to accommodate the delay as the event loop is not over yet, resulting in the users experiencing lags and janks.

The JavaScript thread is responsible for most of the business logic in React Native applications. This is the main thread that needs to be taken care of as a developer. Most performance issues will have a huge, if not a severe frame drop when this thread is "busy".

The JavaScript thread is the main thread that needs to be taken care of as a developer.

Frame Rate#

Open up the developer menu in the app and toggle Show Perf Monitor.

To open the developer menu: Android: Ctrl + M or ⌘ + M | iOS: ⌘ + D

We will notice that there are two different frame rates. One is for JavaScript and the second is for the UI thread.

JS frame rate#

Now on UI, a screen needs to be refreshed at 60FPS (60 times in a second). So that gives approx ~16ms for an event loop to execute whatever is asked of it.

On average, the app takes approximately 4ms - 5ms to do composition, calculate layout changes and render the screen. So this gives us nearly 10ms to execute whatever we want to on the JavaScript thread. Now, this may not seem a lot, but it is - most of the time. And if we want to keep the app responsive, we need to meet this limit. Say, if a task takes 60ms to execute, then the app will drop four frames to accommodate for it.

The JavaScript frame rate helps us understand that something is blocking the JavaScript thread and therefore the app is not being as responsive as it should be.

Frame rate may not show as exactly 60, especially in emulators. Anything above 50fps is fine, in general.

In the Debug module we saw how to troubleshoot JavaScript issues, how to find what is taking time to render, and how to find what is re-rendering.

UI frame rate#

This is the native thread that handles rendering. Remember the UI thread from the React Native architecture in the Real World Apps lesson. Animations such as transitions are done entirely on the main thread, and so they are not impacted by frame drops on the JavaScript thread.

ScrollView also lives on the main thread, so we can scroll even while the JavaScript thread may be busy, keeping the app responsive.

Frame drops in this thread mean the issue is on the native side and the app may be using a significant amount of memory, more than the OS is ready to allocate (yes, mobile operating systems these days do try to limit that). Some common sources of issues can be:

  • Flatlist optimization may be required

  • Too many images, so caching may be needed

  • Compressed images being used

  • SVGs having a lot of paths

  • Animations: try using a library that runs animations on the UI thread in native

Run your animations on the UI thread or use Reanimated if not permitted by React Native's Animated API.

Start a new discussion. All notification go to the author.