How To Optimize The Performance Of PhoneGap Apps

How To Optimize The Performance Of PhoneGap Apps

Despite the increasing processing power of mobile devices, most cross-platform apps cannot fully satisfy the constantly growing demands as for the visual richness combined with good performance on both iOS and Android. How can we resolve the issue? The most obvious answer lies in understanding the specifics of the platform, the wrapper on which the application code is running (mobile WebView), and the corresponding processes.

This article was inspired by our diverse expertise in mobile application development. Here you’ll find problems of code execution, solutions, and helpful tips on optimizing the performance of cross-platform apps based on PhoneGap (a.k.a. Apache Cordova).

Let’s start with the runtime environment in which the application code is running:

#1. Runtime Environment

The whole program code in PhoneGap apps or other types of JS/HTML apps runs in mobile webView, which is a browser built into your application. WebView serves as a wrapper or a virtual runtime environment for the execution of your functional code. Internal limitations and specificity of app execution fully depend on the architecture of the built-in browser. There is no official documentation about browser internals. Most modern browsers work according to the following diagram:
The whole program code in PhoneGap apps or other types of JS/HTML apps runs in mobile webView, which is a browser built into your application. WebView serves as a wrapper or a virtual runtime environment for the execution of your functional code. Internal limitations and specificity of app execution fully depend on the architecture of the built-in browser. There is no official documentation about browser internals. Most modern browsers work according to the following diagram:

It clearly shows 3 stages of the main thread: loading, reflow, repaint. Each of these stages has a great impact on app performance.

  • Loading includes loading the HTML and CSS with the content and design, as well as parsing of the downloaded data.
  • Repaint – actually paint and display.
  • Reflow – the most heavyweight part of the main thread, related to processes such as loading and repaint. Includes the construction of a document object model, which contains all the document data. Creating design rules, applying them to the DOM, creating the render tree, layouting (dividing the render tree into independent and dependent layers for rendering, and their optimization). There is also a Garbage Collector which affects all three stages of the main flow.

All of these stages are crucial, therefore we will give a few practical tips. After showing WHAT should you do, we’ll show WHY you should do it, so we will refer to the theory and browser internals.

#2. Control The Size Of Your DOM

As you could see from the previous scheme, DOM is actually a separate functional mechanism in the browser. Data processing/manipulation takes time because DOM is stored in memory all at once.

The more data you have (the bigger DOM is), the more time it requires for manipulation.

Is there a solution to this situation? Yes, it’s trying to manipulate a more lightweight DOM. There are 4 ways of achieving it:

1. Make your application markup as simple as possible.

Pros: faster and easier development.

Cons: it doesn’t solve the problem completely: the more data there is, the more time it requires for the manipulation, and it isn’t always possible as for functionality and design.

2. Disconnect the unnecessary (currently invisible) branches of the app from the DOM main tree, which repaints.

Pros: it increases the speed of rendering and makes it easier to manipulate the DOM main branch. The DOM-branches under manipulation are not deleted; that’s why they are not recreated while they are being attached or detached. JavaScript code already contains links to DOM branches.

Cons: requires JavaScript implementation.

3. Use classic patterns to represent a large number of “heavy” visual information, for example, you can use Flyweight + factory (adapter) – as it is done in existing mobile platforms.

Pros: it is the best solution to the issue of performance.

Cons: very costly development concerning time resources. Modern UI frameworks implement only the visual design, sometimes including mobile GPU acceleration for faster animation. So we started to develop our own solutions to implement complex UI-patterns for mobile devices (e.g. infinite scroll, view pager or tile set) that are able to work with real data. A good example is our developer toolkit RAD.js.

4. Create page content using templates each time you navigate to another app page.

Pros: it almost solves the problem.

Cons: it adds a delay in template rendering during every transition to another page; because the more complex it is, the longer it takes.
Each of these approaches has the right to exist. But each one has pros and cons, so consider them and select according to the requirements in each particular case.

In most cases we choose the 2nd option – the one with the implementation of detachment and attachment of DOM branches. It is easy and you can see it from the code sample. This.el is a DOM pointer we work with.

There’s no magic – you just use append child and remove child, that’s it. The DOM element is not released by Garbage Collector because there is an external link to it in JavaScript. That is why frequent connection and disconnection of the branches to the DOM doesn’t take much time. This is very important – it reduces the required time at subsequent showing and hiding of elements.

Now a question: how can we optimize an already existing project?

The following illustrations show two variants of using the attaching/detaching approach. On the left you can see loading content to an empty container; on the right – when you already have loaded DOM. You can detach the invisible from the user DOM. A common mistake is the frequent use of custom events in DOM.

#3. Custom DOM Events

A few words about custom events in DOM. They are used in many polyfills for mobile devices – they are heavyweight, so try not to use them too often. During the event distribution in the DOM tree, the browser has to use 2 mechanisms (JavaScript and DOM) together, which takes additional time to synchronize them. It leads to delays.

Also you should note that frequent use of custom DOM events may activate the Garbage Collector which stops all the processes in the browser.

If you need to transfer data between the JavaScript modules of the application regularly or frequently – use the object pool pattern and transmission of JavaScript objects rather than a custom DOM event.

#4. Cache Everything

You should save references to the DOM nodes you constantly work with in JavaScript variables, so to not waste time on querying.

#5. Keep It Simple, Keep It Flat (Rendering)

The simpler the visual style of the app is, the better performance and responsiveness it has. Maybe this is the main reason of the latest trends in design, for example, flat style, or material design by Google. These approaches hardly use rich design with shadows or half-opacity. It simplifies the rasterization algorithm of visualization and reduces the load on the mobile processor. The problem is when the app tries to render a part of shadow or opacity, it has to know the fill color and the color of the background, then the overlay algorithm — it all leads to excessive calculations.

#6. GPU Animation (Rendering)

Most modern mobile devices have Graphics Processor Units (GPUs). Their presence allows you to speed up animations of the apps’ visual parts because it translates your DOM-branches into textures in GPU.

Here you can encounter the following issues:

  1. In CPU we operate DOM objects, in GPU – textures. It means that you can’t manipulate the last ones. You need additional time to transfer changed DOM structures to GPU textures.
  2. It takes time because it requires additional rendering in the device memory.
  3. Thus memory consumption grows.
  4. Try to avoid the accidental transition of the layer to GPU. It can happen when a layer untransferred to GPU overlaps with a transferred one, so you get lags. Meanwhile, the first layer will be automatically transferred to the GPU before the animation and brought back afterward.
  5. It is impossible to speed up everything: for example, items that contain rapidly changing content, instead of acceleration lead to lags due to the 2nd and 3rd reasons.

So be careful and make sure that:

  • There’s no changing data during the CSS animation in accelerated layers because it requires additional rendering.
  • There are no layers not accelerated in the GPU, which partially overlap the accelerated ones — it will cause lags.

#7. Keep Smart CSS Layers (Rendering)

Tip: markup your app so that the frequently changed data is divided into separate smaller layers.
You may also place static content elements on the page (for example, header and footer – it will not affect the result).

You should consider a huge amount of DOM methods lead to reflow. And sometimes it happens with the recalculation of the whole page. But in some cases (for example, when you use position: absolute or fixed) it leads to recalculation of small separate layers only. The rest of the page will not be touched. This mechanism is important for optimization, so let’s consider it in detail.

How exactly does the reflow happen? There are 4 steps:

At the same time, if you use a ”float’ in your CSS for shifting from calculation thread, it takes more time then ”position: absolute or fixed” cases – because the main thread also should be recalculated in the first place. Only afterwards the float element will be reflowed.

So if your application page elements will be animated or have frequently changing content, the most effective way is to put this functionality in a separate CSS layer by assigning to them position: absolute.

#8. Image Scaling (Rendering)

Don’t scale images! It’s better to make an image in several sizes beforehand.

Sometimes developers simply forget about it. But every change means a recalculation at the expense of processing power and time, because most browsers perform all operations in a single thread. We can’t waste our time on additional calculations when we develop apps for mobile devices.

For example, on iOS 7 at 1.3-x, scaling of an image with 500px width takes almost 10 milliseconds on the simulator (on a real device, of course, less time – but it is still an indicator). This is more than half of the animation frame budget. For example, if you have a list of pictures, you won’t be able to get a smooth animation owing to this.

#9. Give It Some Rest (Browser Execution Flow)

If you have a huge undivided flow part, try to use the fragmentation of code into smaller operations. Then run them through the setTimeout () or requestAnimationFrame (). This will allow the browser, which executes the code in your app, to perform critical service operations such as the recalculation in the intervals. In addition, it will smoothen the user experience of your app.

Here is an example of delayed animation. Here we use the left attribute of element BUT the animation is smooth.

Notice that it is recommended to use requestAnimationFrame in cases with animation, because this method is specified for 60 fps. Same for setTimeout, in case you want to split the execution flow. setTimeout has an approximate 4-millisecond delay.

#10. Garbage Collector (Save Memory Patterns)

Try not to create JavaScript objects frequently (in the loop or while returning the results from frequently used functions). The user can see the result as casual small delays in your app — unpredictable and extremely irritable for the user.

Delays happen due to Garbage Collector. It stops all operations in the browser. On mobile devices it works more aggressively than on desktops. So you should consider the specifics of the memory in JavaScript.

#11. Use The Correct Wrapper! PhoneGap vs. CrossWalk

As you can see from everything mentioned above, the runtime environment is very important. That is why you can and you should choose a wrapper for your JavaScript application. At the moment, for example, for Android, we have several options. The most famous are PhoneGap by Adobe and CrossWalk by Intel.

How to speed up PhoneGap apps:

  • Simplify your DOM
  • Manipulate the DOM tree
  • Understand the markup layers
  • Simplify your CSS (by not using shadows and gradients)
  • Use hardware acceleration
  • Cache everything
  • Monitor the work of Garbage Collector
Insights
MVP Lite Approach to Software Development

MVP Lite: Re-engineering of Software Development Approaches

Insights
The Conference for Machine Learning Innovation. Fast and accurate: AI-based video processing session by MobiDev

Join ML Conference: AI-Based Video Processing Session

Insights

IoT Analytics: What Is It And How to Implement It in Your Organization

Want to get in touch?

contact us