AngularJS – ngRepeat Performance Watchers

AngularJS has a directive “ng-repeat” which is very widely used. ng-repeat is used in almost every application but if not used properly can cause various performance issues.

$watch and ng-repeat

The main problem with ng-repeat ism it creates to many watch expression. To understand what is are watches read here.
Lets take a small example

<div ng-repeat='item in array'>
     {{item.name}} -- {{item.date}}
</div>

Suppose if the length of above array is 10, then this ngRepeat creates 10*2 + 1 $watches in angularjs. As you can see such a simple ng-repeat casues 21 watches, anything more complex and with a larger array size will easily add a lot of $watches. On a desktop application this won’t cause any significant slow down, but on mobile application it does slow down the application. On a single page, more than 2000 watches is generally considered bad. Lets see what are the various solution

Easy tips first
ng-repeat track by
ng-repeat has a attribute “track by” with which we can supply a unique id. This reduces the number of dom repaints and dirty checking needed.

<div ng-repeat='item in array track by $index'>
</div>

track by can use any unique id, $index is the most easy one to use. Read More Here

ng-repeat filter
Avoid using ng-repeat filter, it better to pass a filtered array to ng-repeat than using filter

ng-repeat with function

<div ng-repeat='item in getArray()'></div> <!-- Don't use this -->

It always better to use array as a variable rather than returning it from a function.

Batarang

Batarang is a very useful chrome plugin which allows you to see the number of watches, scope model etc. It show which watchExpression is taking most amount of time. This is a very useful tool for debugging. Below are screenshots to see batarang in action.

One Time Watches

One time watches, these are directives/expression which execute $watch only one and then get removed from scope. There are various ways of doing this

Bindone
Bindonce is a great library https://github.com/Pasvaz/bindonce which removes all watches from your ng-repeat. You need to use some custom directives like bo-if, bo-show, bo-html etc. This is a must use library for ng-repeat with large data sets. Go through its documentation and understand how to use it.

Watch Fighters
Watch Fighter is another great library with a custom set of directives https://github.com/abourget/abourget-angular which has a custom set of directives for one time watches.

:: notation in angularjs
angularjs 1.3 introduced :: notation for one time binding.

<div ng-repeat='item in ::array'>
      {{::item.name}} -- {{::item.date}}
</div>

Your Custom Watchers
If you are using custom watchers in your application, then you stop watches by calling their return function. As seen below.

var watcher = $scope.$watch('variable',function(newVal,oldVal){
});
$scope.stop = function(){
  watcher();
};

Here is the full code for this