Skip to content

Instantly share code, notes, and snippets.

@felippenardi
Last active February 1, 2024 11:06
Show Gist options
  • Save felippenardi/ea301e8a27155ae19b79 to your computer and use it in GitHub Desktop.
Save felippenardi/ea301e8a27155ae19b79 to your computer and use it in GitHub Desktop.
Benchmarking AngularJS performance

Benchmarking AngularJS performance

Things to optmize

  • Use one-time-bind on expressions ( {{::value}} )
  • Replace $scope.$apply() with $scope.$digest() whenever possible
  • Move filters to controllers

Measuring Watch list

To get the total watchers on the current page, you can run this script on the browser console:

function getWatchers(root) {
  root = angular.element(root || document.documentElement);

  var watcherCount = 0;
 
  function getElemWatchers(element) {
    var isolateWatchers = getWatchersFromScope(element.data().$isolateScope);
    var scopeWatchers = getWatchersFromScope(element.data().$scope);
    var watchers = scopeWatchers.concat(isolateWatchers);
    angular.forEach(element.children(), function (childElement) {
      watchers = watchers.concat(getElemWatchers(angular.element(childElement)));
    });
    return watchers;
  }
  
  function getWatchersFromScope(scope) {
    if (scope) {
      return scope.$$watchers || [];
    } else {
      return [];
    }
  }
 
  return getElemWatchers(root);
}
getWatchers().length

Measuring Time

To get information of time that an operation takes, you use one of these two methods:

Manually

Run:

window.performance.mark('begin_operation');

Just before the operation starts. Then:

window.performance.mark('finish_operation');

When it ends. Then:

window.performance.measure('operation', 'begin_operation', 'finish_operation')

The result will be stored on:

window.performance.getEntriesByType('measure')[0].duration

The output is in miliseconds with microseconds units.

Automatically

1- Go to you chrome Profiles tab on developer tools 2- Click on record 3- Do an specific operation 4- Pause recording

The idle time can be ignored, what we are looking for here is the program time.

You can see how much time every operation took and even some suggestion right away on what to improve (the exclamation marks).

Improving Peformance

Set debugInfoEnabled to false

You might have noticed that Angular addes a few classes like "ng-binding", "ng-scope", and a few others to your tags. This happen on compile time where, for debugging purposes, Angular attach those class. But it is also attaching the entire scope object to every element (which help us access any elemnt's scope via console with: angular.elemnt(<HTML NODE>).scope()).

But that comes with a performance cost. A cheap way to speed up you Angular app, in the cases where you have several bindings, is to disable it like so:

app.config(['$compileProvider', function ($compileProvider) {
  // disable debug info
  $compileProvider.debugInfoEnabled(false);
}]);

You will not have acess to element's scope from the DOM, and protractor and Baratang will not work. For that reason, you will want to only enable it in production. But, even if in Production if you need to debug your app, you can call from the console: angular.reloadWithDebugInfo(). Voialá! There you have you debug classes and scopes attached to elements again.

Reference: http://blog.thoughtram.io/angularjs/2014/12/22/exploring-angular-1.3-disabling-debug-info.html

Determine when a model should be updated using ng-model-option

https://docs.angularjs.org/api/ng/directive/ngModelOptions

By default, any change to a model will trigger an entire digest loop. For example, If you know a a field change can wait until the user leave the field, you can set ng-model-option to only update the model on blur event.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment