Architecting Performant HTML5 Mobile Applications on Force.com: Part 3

Are you looking to architect performant HTML5 mobile apps for Force.com? In part 3 of this series of best practices from MVP extraordinaire, Keir Bowden, learn about single page versus multi-page applications and the use of Knockout, an M-V-VM library, to avoid writing lots of DOM manipulation JavaScript.

Part 1 of this series covered the reasons why performance matters in the mobile world, and gave some high level advice on how to re-architect applications for mobile devices. Part 2 of this series covered some best practices around accessing data from Salesforce, using JavaScript and rendering images. This post covers single page versus multi-page applications and the use of Knockout, an M-V-VM library, to avoid writing lots of DOM manipulation JavaScript.

Note: This post is from Keir Bowden (aka Bob Buzzard), a Force.com MVP, Salesforce Certified Technical Architect and CTO of BrightGen, a Platinum Cloud Alliance partner in the United Kingdom. He has been solving business problems with the Force.com platform since 2008 and building hybrid and HTML5 mobile applications since late 2010. He is a regular blogger on Apex, Visualforce and Salesforce1 solutions at The Bob Buzzard Blog.

Single-page versus Multi-page Applications

A Multi-Page Application (MPA) follows the traditional client-server architecture — as users navigate around the application, requests are sent to the Salesforce1 platform to retrieve the next Visualforce page, which is then returned to the browser. The following diagram shows the client/server interaction for a multi-page application that presents a list of accounts to a user who can then edit account details:

The request response flow is as follows:

  1. The user opens the application which retrieves the account list page.
  2. The user chooses an account to edit, which retrieves the account detail page and the view state containing the data for the page.
  3. The user updates the account detail, which posts the updated information and view state. This returns the account detail page and the updated view state.
  4. The user returns to step 1 to choose another account to edit.

While the page markup and resources are lightweight (as they only contain the information for the particular page) the application state is maintained in the Visualforce view state, which is sent back to the server with each request. As detailed in part 1 of this blog series, performant HTML5 web applications should try to reduce the number of round trips to the server, and should avoid using the Visualforce view state as this is a heavyweight resource for the device to manage. In a truly mobile environment, a multi-page application is likely to lead to slow response and request timeouts and for these reasons should be avoided.

A Single-Page Application (SPA) follows an application plus API architecture — all pages are delivered to the client as part of the initial request. This means that while the initial page request is longer, as all markup and resources used by the application are retrieved in a single request, navigation between pages is carried out via JavaScript using markup and resources that are already stored on the device. Data is retrieved from the server in a single API request, maintained in the client through JavaScript business logic and saved back to the server in a single API request. The following diagram shows the single page equivalent of the account maintenance multi-page application:

The request response flow is as follows:

  1. The user opens the application which retrieves all pages for the application.
  2. JavaScript remoting is used to retrieve the details of all accounts and store the results in JavaScript objects.
  3. JavaScript loads the first page into the DOM and populates the account list.
  4. The user chooses an account to edit.
  5. JavaScript loads the account detail page into the DOM and populates details of the selected account.
  6. The user updates the account detail, which updates the JavaScript object for the account.
  7. The user returns to step 4 to select another account to edit.
  8. When all changes have been made, the user saves all updated accounts via JavaScript remoting.

Single Page Applications require more device memory, as the entire application is maintained in the DOM and all application data is stored locally. They are also long lived, which means that any JavaScript memory leaks will accumulate during the application lifespan, reducing the amount of memory the browser has available to manage the DOM and data. Profiling the memory usage of an application is an important part of the development process for a performant HTML5 mobile application. For more information on profiling, see:

https://developer.chrome.com/devtools/docs/javascript-memory-profiling
http://www.bluewire-technologies.com/2013/resolving-memory-leaks/

Single Page Applications are the approach I would always recommend for an application that is used in a truly mobile environment. Even if the user’s connection drops completely, unless this happens during the initial page or data request, or while data is being saved, the user will be able to continue working without interruption.

Single page applications deliver all logical pages in a single physical page, and typically use a combination of CSS and JavaScript to transition between logical pages. A number of frameworks exist which offer this capability, such as Ionic, JQuery Mobile and the Intel App Framework. For the examples in this blog, I’ll be using JQuery Mobile as it is the framework that I have been using for a number of years to build mobile applications. For details of how to build mobile Visualforce applications using the Ionic framework, take a look at Raja Rao DV’s post.

Logical pages are delivered to the JQuery Mobile framework in a single physical Visualforce page as a series of stacked <div> elements, each with a data-role attribute of “page”:

<div data-role="page" id="page1">
  <div data-role="header">
    <h1>Page 1</h1>
  </div> <!--  /header -->
  <div data-role="content">
    <h2>Welcome to Page 1</h2>
    <p>Press the button to navigate to the next page.</p>
    <p><a href="#page2" class="ui-btn ui-btn-inline ui-shadow">Page 2</a></p>
  </div> <!-- /content -->
</div> <!-- /page -->

<div data-role="page" id="page2">
  <div data-role="header">
    <h1>Page 2</h1>
  </div> <!--  /header -->
  <div data-role="content">
    <h2>Welcome to Page 2</h2>
    <p>Press the button to go back.</p>
    <p><a href="#page1" class="ui-btn ui-btn-inline ui-shadow">Page 1</a></p>
  </div> <!-- /content -->
</div> <!-- /page -->

JQuery Mobile will hide all <div> elements aside from the first. Executing the example code above will display the element with the id of page1, while clicking the Page 2 button will hide the element with the id of page1 and display the element with the id of page2, as shown in the following screen shots:

The framework will also provide an animated transition, such as a fade or slide, when replacing one logical page with another.

Separating Presentation from Content

When an HTML5 application retrieves data from the Salesforce1 platform, it must manipulate the DOM via JavaScript to insert or replace the data in the appropriate part of the page, leading to repeated boilerplate code even when using a library such as JQuery. Updating the DOM in response to several changes to a complex object graph results in multiple, sometimes intricate, selectors which can slow down page rendering.

Knockout is a Model-View-View Model framework that addresses this issue by providing a mechanism for declaratively binding data to user interface elements, automatically updating the user interface when the underlying data changes. There are a number of other JavaScript frameworks that separate the model from the view and business logic, including Backbone, Ember, Angular and CanJS. I favour Knockout for the simple reason that I know it well, having used it for several years. For more information on Knockout, and an excellent set of tutorials see http://knockoutjs.com/.

The key to Knockout is the view model. This contains the data being managed and the methods that carry out operations on that data -– essentially a controller in JavaScript. The following code snippet is an example View Model that manages two properties:

function SimpleViewModel() 
{
    this.firstPage='Page 1';
    this.secondPage='Page 2';
}

To activate Knockout, the applyBindings method must be executed, passing an instance of the View Model:

ko.applyBindings(new SimpleViewModel());

The Single Page Application example code from above can then be rewritten as:

<div data-role="page" id="page1">
  <div data-role="header">
    <h1 data-bind="text: firstPage"></h1>
  </div> <!--  /header -->
  <div data-role="content">
    <h2>Welcome to <span data-bind="text: firstPage"></span></h2>
    <p>Press the button to navigate to the next page.</p>
    <p><a href="#page2" class="ui-btn ui-btn-inline ui-shadow" data-bind="text: secondPage">Page 2</a></p>
  </div> <!-- /content -->
</div> <!-- /page -->

<div data-role="page" id="page2">
  <div data-role="header">
    <h1 data-bind="text: secondPage"></h1>
  </div> <!--  /header -->
  <div data-role="content">
    <h2>Welcome to <span data-bind="text: secondPage"></span></h2>
    <p>Press the button to go back.</p>
    <p><a href="#page1" class="ui-btn ui-btn-inline ui-shadow" data-bind="text: firstPage"></a></p>
  </div> <!-- /content -->
</div> <!-- /page -->

When the page is rendered, the elements with the data-bind attribute of "text: firstPage" or "text: secondPage" have their contents automatically set to the value of the property from the view model without any additional JavaScript. The page names are now decoupled from the content, and may be altered simply by changing the property values in the view model.

The above example demonstrated a static binding, but one of the main benefits of Knockout identified above is that the user interface automatically updates when the view model changes. This is achieved through use of observables — properties that notify subscribers about changes.

The following view model defines an observable property named ‘product’, and a function that sets the value of ‘product’ to an element from a list of Salesforce products:

function ObservableViewModel() 
{
  var self=this;
  self.products=['Sales Cloud', 'Service Cloud', 'Marketing Cloud', 
                 'Salesforce1 Platform'];
  self.idx=0;
  self.product=new ko.observable();

  self.setProduct=function()
  {
    self.product(self.products[self.idx++]);
    self.idx%=4;
  }

  self.setProduct();
}

ko.applyBindings(new ObservableViewModel());

The product observable is then bound to an element on the page and a button provided to execute the setProduct method to update the observable value:

<h2><span data-bind="text: product"></span></h2>
<p>Press the button to update the product.</p>
<p><button class="ui-btn ui-btn-inline ui-shadow" 
           data-bind="click: setProduct">Update</button></p>

Clicking the button advances the product observable to the next value from the list, which automatically updates the value on the page without the need for any JavaScript to locate the element and change it, as shown in the following screenshots:

Like any other framework, Knockout will not be magically performant in all situations. When managing extremely simple data models, the additional overhead introduced by the framework outweighs the benefit of reduced DOM manipulation. As applications become larger and more complex, it becomes important to understand a little more about how the framework operates to understand the amount of work it is carrying out. Ryan Niemeyer has written a number of blog posts outlining performance issues encountered as applications scale and associated workarounds, as well as a tips for improving Knockout performance in general.

Knockout is at its heart a data-binding library — a building block of an HTML5 mobile application. It doesn’t provide functionality like routing and animations, but integrates well with other libraries that do. For this reason, Knockout is particularly suited to adding data-binding capabilities to existing applications. For development of a brand-new application, the effort required to identify and integrate a collection of libraries is not insignificant, in which case a full featured framework such as Angular may be more suitable.

An example HTML5 mobile survey application built as an SPA using JQuery Mobile and Knockout is available on github.

About the Author

Keir Bowden (aka Bob Buzzard), is a Force.com MVP, Salesforce Certified Technical Architect and CTO of BrightGen, a Platinum Cloud Alliance partner in the United Kingdom. He has been solving business problems with the Force.com platform since 2008 and building hybrid and HTML5 mobile applications since late 2010. He is a regular blogger on Apex, Visualforce and Salesforce1 solutions at The Bob Buzzard Blog.

This post was published in conjunction with the Technical Enablement team of the salesforce.com Customer-Centric Engineering group. The team’s mission is to help customers understand how to implement technically sound salesforce.com solutions. Check out all of the resources that this team maintains on the Architect Core Resources page of Salesforce Developers.

Leave your comments...

Architecting Performant HTML5 Mobile Applications on Force.com: Part 3