Enact Performance Guide

Overview

Performance is a critical portion of any application. With Enact you can use all the same tools as you normally would for React. We recommend reading this first to gain familiarity with performance testing in React.

Some important things to understand are how to use React’s performance timeline, understand how to use shouldComponentUpdate to avoid reconciliation, and learning to not mutate data if possible.

Enact provides some useful tools to help you achieve faster performance.

Managing async calls

Job is a class in our core module. It’s a useful wrapper for async things like setTimeout and requestIdleCallback. We also provide functionality like throttling that we’ll describe below.

Idle

In some modern browsers, there is support for requestIdleCallback. In Job we can access this through idle. This calls a function only when the browser is in an idle state. This is great for functions that don’t need to be called immediately and can be called asynchronously without blocking the main thread.

import {Job} from '@enact/core/util';

const importantButNotHighPriority = new Job(doSomething);

this.importantButNotHighPriority.idle();

Throttle

Sometimes a function will execute too often. For instance, let’s take something like an onWheel event. This event may fire too often for out liking, causing reduced performance and ultimately a bad user experience. To throttle it, we can do something like:

import {Job} from '@enact/core/util';

// We can set up Job like so this.
// The 2nd argument will set how often the event should fire in milliseconds
const throttleEvent = new Job(doSomething, 100);

// When we run the event we can do this.
// This will run the event every 100ms even if we fire it more often.
const handleWheel = () => {
    this.throttleWheelInc.throttle();
}

// render method
<div onWheel={handleWheel}>Wheel Div</div>

Dealing with long lists of data

React recommends using virtualized lists for rendering long lists of data. This is for a good reason. Virtualized lists drastically reduce the number of repainting and reflowing that normally cause browsers to slow down. Enact includes our own implementation of a VirtualList that makes it easy to achieve this performance boost.

Production Packing

Enact’s cli tool provides a way to create, test, and build applications. When packing your application for production, cli makes it very simple.

To build your app in production mode, run the command below. This will minify and “uglify” all of your code and bundle it into a single file.

enact pack --production

Isomorphic

To generate a static version of the first page, you can use our isomorphic flag. This will create an HTML representation of your entry page, allowing users to see the initial content much faster.

enact pack --production --isomorphic

Using timestamps

perfNow is useful for getting higher resolution timestamps to see how long a set of functions take. It’s a nice little wrapper around window.performance.now that will fall back to Date.now.

import {perfNow} from '@enact/core/util';

const firstTime = perfNow();

const secondTime = perfNow();

const difference = secondTime - firstTime;

Working with webOS

If you’re developing for webOS, using Enact, we have some specialized tools to help you with that as well.

We can run a log to see how long an application took to launch:

pmctl perflog-report

This will print out some logs that looks like this:

Type: AppLaunch
Group: com.webos.app.coolapp
Start time: 2578.59
Process                        MsgID                     Time(s)  +Diff(s)  Extra
surface-manager-starfish       IM_KEY_INPUT              0.0      +0.0      key_value:0 key_code:272
sam                            APP_LAUNCH                0.021    +0.021    status:start_prelaunching
sam                            APP_LAUNCH                0.03     +0.009    status:start_memory_checking
sam                            APP_LAUNCH                0.032    +0.002    status:start_launching
WebAppMgr                      APPLAUNCH_START           0.033    +0.001    APP_ID:com.webos.app.coolapp
WebAppMgr                      APPLOADED                 1.665    +1.632    APP_ID:com.webos.app.coolapp URL:file:///usr/webos/applications/com.webos.app.coolapp/index.html PID:24274
sam                            GET_FOREGROUND_APPINFO    1.838    +0.173
WebAppMgr                      WINDOW_FOCUSIN            1.84     +0.002    APP_ID:com.webos.app.coolapp
Elapsed time (s) : 1.840

While this is great, we may want to add some custom timestamps to this log. To achieve this we can simply add perfLog from the webos package. It takes three arguments: perfLog(MsgID, Type, Group).

We can use it like this:

import {perfLog} from '@enact/webos/pmloglib'

perfLog('APP_INTERACTIVE', 'AppLaunch', 'com.webos.app.coolapp');

The above will now output the same thing we previously had, but with more info.

Process                        MsgID                     Time(s)  +Diff(s)  Extra
surface-manager-starfish       IM_KEY_INPUT              0.0      +0.0      key_value:0 key_code:272
sam                            APP_LAUNCH                0.009    +0.009    status:start_prelaunching
sam                            APP_LAUNCH                0.019    +0.01     status:start_memory_checking
sam                            APP_LAUNCH                0.021    +0.002    status:start_launching
WebAppMgr                      APPLAUNCH_START           0.022    +0.001    APP_ID:com.webos.app.coolapp
WebAppMgr                      APPLOADED                 0.6      +0.578    APP_ID:com.webos.app.coolapp URL:file:///usr/palm/applications/com.webos.app.coolapp/index.html PID:20509
sam                            GET_FOREGROUND_APPINFO    1.188    +0.588
WebAppMgr                      WINDOW_FOCUSIN            1.377    +0.189    APP_ID:com.webos.app.coolapp
WebAppMgr                      APP_INTERACTIVE           2.867    +1.49
Elapsed time (s) : 2.867