Javascript Frameworks: Thinking Performance Can Save Your Project

Written by Andrei Verazub on 15 Mar 2016
57,506 Views • Web Development

Alright, let’s put it straight: PM’s and developers don’t always ponder performance issues while choosing a JavaScript framework for their project. Instead, they stick to we’ll-optimize-that-later approach. There are several reasons behind this: developers work on machines faster than that of an average user, they use low data volumes for testing and they think algorithms rather than performance.

But performance is what the user sees, feels and judges firsthand. Offering a website development service to create complex portals with reach interfaces for established enterprises, we at ScienceSoft remind ourselves of this every day.

Putting off performance issues is dangerous, because once, out of the blue, the framework’s limitations strike you, there will be nothing to optimize. Simple as that. Dead end. Point of no return. Switch to another framework or die, which, in your case, might imply the same thing.

The tricky thing here is that you won’t be able to spot potential performance problems until you need to create complex forms or UI behavior. When spotted during acceptance testing, the debacle of a form with tens of elements loading for several seconds will leave you and your customer in a state of a slight confusion (oops!).

So what do you do? You carefully consider the architectural limitations of frameworks in question – upfront.

In this article, using Ext JS, React and Knockout as examples from our experience, we touch upon the possible performance issues you may encounter building modern and advanced UIs.

Ext JS

A heavy framework, Ext provides powerful tools to create fancy UI elements quickly and easily. We had been using it for 1.5 year to build a medical practice management web software that would deal with large amounts of data, such as patient records, physician base, reports and many more. It went smoothly until we needed to build forms with over 50 fields – it would take 4-7 sec for them to load.

This happened largely because Ext automatically created numerous DOM objects and did a lot of costly DOM manipulations (for example, adding new nodes to DOM) to update the UI. Whatever out-of-the-box component we used, be it a button or a form field, the framework would naturally generate a bunch of unoptimized HTML code. All this happened to be a burden on the browser and slowed down the layout rendering significantly. We tried to optimize it by using a filter to stop the calculations until the framework would finish the rendering, but finally it wouldn’t add much to the needed level of performance. Bear in mind, that was a complex software with large forms and multiple pop-ups. At some point, realizing that we could not increase Ext performance any more, we decided to switch to React. And this had been a painful transition.

This limitation had also been one of the reasons why we abandoned Ext in a project to create Enonic eXperience Platform – an interactive and scalable CMS.

Apart from that, in 5 recent Ext projects we haven’t encountered any major performance issues.

React

Unlike other JS frameworks, React avoids creating DOM nodes in response to a state change. Rather, it uses a virtual DOM – what React authors call “a descriptor of a DOM subtree rendered in the browser”. Here is what stands behind the concept according to the Founding Fathers:

This parallel representation allows React to avoid creating DOM nodes and accessing existing ones, which is slower than operations on JavaScript objects. When a component's props or state change, React decides whether an actual DOM update is necessary by constructing a new virtual DOM and comparing it to the old one. Only in the case they are not equal, will React reconcile the DOM, applying as few mutations as possible.

This allows for unprecedented performance. So, React was a perfect match, as our medical practice management software dealt with large data volumes. In the course of the other React project (we’ve had only two so far), an order management system for mobile diagnostic imaging, the framework performed smoothly, as well.

React, however, is not a framework in its strict sense – it has no out-of-the-box components, and you need to create every element from scratch. Thus, using it can be expensive for projects with more trivial UI requirements.

Knockout

Knockout’s key concept lies in the support of two-way data-binding. The idea is that for each model developers wrap properties in observables (in fact, Knockout is an implementation of the “Observable” design pattern), which, in turn, react to events and change the DOM, whereas observables also listen to DOM changes to update the model. Let’s go into more details here to find out what performance problems may pop up. Have a look:

<p>First name: <input data-bind="value: firstName" /></p>
<h2>Hi, <span data-bind="text: firstName "> </span>!</h2>

 

// Here's my data model
var ViewModel = function(first) {
    this.firstName = ko.observable(first); 
};
ko.applyBindings(new ViewModel("John")); 

Usually, most web applications operate arrays of data. When using Knockout, observableArrays come in handy. These are observables with some additional methods to deal with common array manipulation tasks.

Let’s say we have a simple view model that contains an observable array and a computed observable (i.e. an observable that is dependent on one or more other observables and reacts to change in any of these dependencies):

var ViewModel = function() {
  this.animals = ko.observableArray([
    new Animal("Josh", "Cat"),
    new Animal ("Chester", "Dog"),
    new Animal ("Bungles", "Cat")
  ]);

  this.cats = ko.computed(function() {
    return ko.utils.arrayFilter(this. animals (), function(item) {
      return item.type() === "Cat";
    });
  };
};

Every time we push a new animal to the observable array, the computed field redefines its value. Moreover, if we bind our array to the UI, each push will make the template binding do its work to determine that only one new item has been added. This may lead to a decreased performance.

So, a better way is to get a reference to the underlying array, push new values and then check whether the observable array has mutated:

this.addNewAnimals = function(newAnimals) {
  var item, underlyingArray = self.animals();
  for (var i = 0, j = newAnimals.length; i < j; i++) {
    animal = newAnimals [i];
      underlyingArray.push(new Animal(animal.name, animal.type));
    }
  self.items.valueHasMutated();
};

Now, our subscribers will only receive one notification indicating that the array has changed.

Knockout provides some bindings that you can use in templates – for example, “if” and “with”, which is a useful yet performance-risky feature. Commonly, developers use the “if” binding to show/hide the entire area that depends on observableArray items:

<!-- ko if: items().length -->
<h2>Items</h2>
<ul data-bind="foreach: items">
  <li data-bind="text: name"></li>
</ul>
<!-- /ko -->

Here, each time the “items” array changes, the binding will re-render its template. As re-rendering may eat up resources and thus compromise performance, the solution is to use “visible binding” instead of “if”.

Conclusion

The crux here is not to show the pros and cons of a particular JS framework but to emphasize that PM’s and development crews must ponder performance limitations while choosing a tool. It doesn’t mean there is a magic bullet framework for ultimate performance, as you still have to think about staying within budget and time, and some framework choices may be too heavy to go with. But if you make the wrong decision and performance issues come out of nowhere, you will fail to deliver. You might be lucky if they don’t, though, but why gamble?

Join the discussion

Comments will be moderated and rel="nofollow" will be added to all links. You can wrap your coding with [code][/code] to make use of built-in syntax highlighter.