MOCKSTACKS
EN
Questions And Answers

More Tutorials









Angular Profiling and Performance

Simple Performance Improvements

1) Use ng-repeat sparingly


Using ng-repeat in views generally results in poor performance, particularly when there are nested ng-repeat's.

This is super slow!


<div ng-repeat="user in userCollection">
 <div ng-repeat="details in user">
 {{details}}
 </div>
</div>

Try to avoid nested repeats as much as possible. One way to improve the performance of ng-repeat is to use track by $index (or some other id field). By default, ng-repeat tracks the whole object. With track by, Angular watches the object only by the $index or object id.

<div ng-repeat="user in userCollection track by $index">
 {{user.data}}
</div>

Use other approaches like pagination, virtual scrolls, infinite scrolls or limitTo: begin whenever possible to avoid iterating over large collections.

2) Bind once


Angular has bidirectional data binding. It comes with a cost of being slow if used too much.

Slower Performance


<!-- Default data binding has a performance cost -->
<div>{{ my.data }}</div>

Faster Performance (AngularJS >= 1.3)


<!-- Bind once is much faster -->
<div>{{ ::my.data }}</div>
<div ng-bind="::my.data"></div>
<!-- Use single binding notation in ng-repeat where only list display is needed -->
<div ng-repeat="user in ::userCollection">
 {{::user.data}}
</div>

Using the "bind once" notation tells Angular to wait for the value to stabilize after the first series of digest cycles. Angular will use that value in the DOM, then remove all watchers so that it becomes a static value and is no longer bound to the model.

The {{}} is much slower.
This ng-bind is a directive and will place a watcher on the passed variable. So the ng-bind will only apply, when the passed value does actually change.

The brackets on the other hand will be dirty checked and refreshed in every $digest, even if it's not necessary.

3) Scope functions and filters take time


AngularJS has a digest loop. All your functions are in a view and filters are executed every time the digest cycle runs. The digest loop will be executed whenever the model is updated and it can slow down your app (filter can be hit multiple times before the page is loaded).

Avoid this

:
<div ng-controller="bigCalulations as calc">
 <p>{{calc.calculateMe()}}</p>
 <p>{{calc.data | heavyFilter}}</p>
</div>

Better approach


<div ng-controller="bigCalulations as calc">
 <p>{{calc.preCalculatedValue}}</p>
 <p>{{calc.data | lightFilter}}</p>
</div>

Where the controller can be:


app.controller('bigCalulations', function(valueService) {
 // bad, because this is called in every digest loop
 this.calculateMe = function() {
 var t = 0;
 for(i = 0; i < 1000; i++) {
 t += i;
 }
 return t;
 }
 // good, because this is executed just once and logic is separated in service to keep the
controller light
 this.preCalulatedValue = valueService.valueCalculation(); // returns 499500
});

4) Watchers


Watchers tremendously drop performance. With more watchers, the digest loop will take longer and the UI will slow down. If the watcher detects change, it will kick off the digest loop and re-render the view.

There are three ways to do manual watching for variable changes in Angular.

$watch() - watches for value changes

$watchCollection() - watches for changes in collection (watches more than regular $watch)

$watch(..., true) - Avoid this as much as possible, it will perform "deep watch" and will decline the performance (watches more than watchCollection)

Note that if you are binding variables in the view you are creating new watches - use {{::variable}} to prevent creating a watch, especially in loops.

As a result you need to track how many watchers you are using. You can count the watchers with this script (credit to @Words Like Jared Number of watchers)

(function() {
 var root = angular.element(document.getElementsByTagName('body')),
 watchers = [],
 f = function(element) {
 angular.forEach(['$scope', '$isolateScope'], function(scopeProperty) {
 if(element.data() && element.data().hasOwnProperty(scopeProperty)) {
 angular.forEach(element.data()[scopeProperty].$$watchers, function(watcher) {
 watchers.push(watcher);
 });
 }
 });
 angular.forEach(element.children(), function(childElement) {
 f(angular.element(childElement));
 });
 };
 f(root);
 // Remove duplicate watchers
 var watchersWithoutDuplicates = [];
 angular.forEach(watchers, function(item) {
 if(watchersWithoutDuplicates.indexOf(item) < 0) {
 watchersWithoutDuplicates.push(item);
 }
 });
 console.log(watchersWithoutDuplicates.length);
})();


Conclusion

In this page (written and validated by ) you learned about AngularJS Profiling and Performance . What's Next? If you are interested in completing AngularJS tutorial, your next topic will be learning about: AngularJS Performance Profiling.



Incorrect info or code snippet? We take very seriously the accuracy of the information provided on our website. We also make sure to test all snippets and examples provided for each section. If you find any incorrect information, please send us an email about the issue: mockstacks@gmail.com.


Share On:


Mockstacks was launched to help beginners learn programming languages; the site is optimized with no Ads as, Ads might slow down the performance. We also don't track any personal information; we also don't collect any kind of data unless the user provided us a corrected information. Almost all examples have been tested. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. By using Mockstacks.com, you agree to have read and accepted our terms of use, cookies and privacy policy.