Turn the performance knob to 10

Dr. Gleb Bahmutov PhD

KENSHO

  ―11 

Kensho financial insight

Boston / NYC / SF

Kensho        Angular

Make your app faster

  • Upgrade Angular version

  • Minimize number of watchers

  • Use `track by`

  • Precompute filter expressions

  • Limit DOM to visible elements

How to approach the performance optimization?

Kensho        Angular

Angular app optimization

  • Live app profiling

  • "Angular plus React equals Speed" revisited

  • A story of failure and redemption

Kensho        Angular

PRIMES !!!

Kensho        Angular

"Finding 1000 primes takes a long time ..."

- client

CHROME > DEVTOOLS > SOURCES > SNIPPETS

How many watchers are there?

How long does digest take?

MY PROFILING RULES

PROFILE IN A "CLEAN" BROWSER

PROFILE THE ACTUAL APPLICATION

OPTIMIZE THE TOP BOTTLENECK FIRST

Kensho        Angular

Your application should have "ports" for performance diagnostics

Kensho        Angular

Automatic

car adapter

i.e. Async methods should return / store a promise on the scope

Kensho        Angular

console.profile('action');
$q.when(scope.foo())
  .finally(function () {
    console.profileEnd('action');
  });

Kensho        Angular

Extra code for message-passing actions

Angular 1.x - 15 seconds

React - 0.5 seconds

Idle digest cycle 15ms

Digest cycle runs 1500 times

There are 5000 watchers

Why so many digest cycles?

$scope.cellClicked = function() {
    // Simulate an AJAX request:
    $timeout(function() {
        $scope.status.searchResults = ...;
    }, randomMillis());
}

Do not run digest each time

$scope.cellClicked = function() {
    // Simulate an AJAX request:
    $timeout(function() {
        $scope.status.searchResults = ...;
    }, randomMillis(), false);
}

Table update runs in 0.5 seconds

Do not run digest after each $http

$http.useApplyAsync(true);

Angular grid load: 650ms

React grid load: 150ms

<tr ng-repeat="hour in hours">
    <td ng-repeat="day in days">
        <my-calendar-cell hour="{{hour}}" 
            day="{{day}}"></my-calendar-cell>
    </td>
</tr>

"Without the included ng-repeat Angular 1 would be hailed as the fastest Web framework ever"

- me

Standard ng-repeat tricks

<tr ng-repeat="hour in ::hours track by $index">
    <td ng-repeat="day in ::days track by $index">
        <my-calendar-cell hour="{{::hour}}" 
            day="{{::day}}"></my-calendar-cell>
    </td>
</tr>

Hmm, are we updating DOM on each table cell creation?

boom-repeat

<tr boom-repeat="hour in hours">
    <td boom-repeat="day in days">
        <my-calendar-cell hour="{{hour}}" 
            day="{{day}}"></my-calendar-cell>
    </td>
</tr>

Do not attach the list to the DOM until all items are ready

(benv + jsdom + browserify - Node parts)

Hey, do your part!

N web workers

Load

Angular 1.x app

Rendering parts in N workers

Look at the big picture, not hacks

<ul class="list">
  <li class="person">
    <div class="first">John</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
  <li class="person">
    <div class="first">Mary</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
</ul>

Static prototype

designer

Making an Angular app

<ul class="list">
  <li class="person">
    <div class="first">John</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
  <li class="person">
    <div class="first">Mary</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
</ul>
<ul class="list">
  <li ng-class="..." ng-repeat="person in people">
    <div ng-class="...">{{ person.first | ... }}</div>
    <div ng-class="last">{{ person.last | ... }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>

Live application

designer or developer

Making an Angular app

<ul class="list">
  <li class="person">
    <div class="first">John</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
  <li class="person">
    <div class="first">Mary</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
</ul>
<ul class="list">
  <li ng-class="..." ng-repeat="person in people">
    <div ng-class="...">{{ person.first | ... }}</div>
    <div ng-class="last">{{ person.last | ... }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>

First performance optimization

<ul class="list">
  <li ng-class="computed" ng-repeat="person in people track by person.id">
    <div ng-class="first-computed">{{:: person.first-computed }}</div>
    <div ng-class="last-computed">{{:: person.last-computed }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>

developer

Making an Angular app

<ul class="list">
  <li class="person">
    <div class="first">John</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
  <li class="person">
    <div class="first">Mary</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
</ul>
<ul class="list">
  <li ng-class="..." ng-repeat="person in people">
    <div ng-class="...">{{ person.first | ... }}</div>
    <div ng-class="last">{{ person.last | ... }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>

Second performance optimization

<ul class="list">
  <li ng-class="computed" ng-repeat="person in people track by person.id">
    <div ng-class="first-computed">{{:: person.first-computed }}</div>
    <div ng-class="last-computed">{{:: person.last-computed }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>

good developer

// no need to run global digest
$timeout(..., ms, false);
// combine digests after HTTP
$http.useApplyAsync(true);

Making an Angular app

Making an Angular app

<ul class="list">
  <li class="person">
    <div class="first">John</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
  <li class="person">
    <div class="first">Mary</div>
    <div class="last">Smith</div>
    <img class="avatar" src="..." />
  </li>
</ul>
<ul class="list">
  <li ng-class="..." ng-repeat="person in people">
    <div ng-class="...">{{ person.first | ... }}</div>
    <div ng-class="last">{{ person.last | ... }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>
<ul class="list">
  <li ng-class="computed" ng-repeat="person in people track by person.id">
    <div ng-class="first-computed">{{:: person.first-computed }}</div>
    <div ng-class="last-computed">{{:: person.last-computed }}</div>
    <img ng-class="..." ng-src="..." />
  </li>
</ul>
// no need to run global digest
$timeout(..., ms, false);
// combine digests after HTTP
$http.useApplyAsync(true);

Designer!

Developer

UI / UX

Performance

Making an X app

var HelloMessage = React.createClass({
  render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});
ReactDOM.render(<HelloMessage name="John" />, mountNode);

Developer

UI / UX / Performance

Angular: making quickly the right app

2

Kensho        Angular

Turn the performance knob to 10

  ―11 

Kensho        Angular