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
[js]
<div ng-repeat=’item in array’>
{{item.name}} — {{item.date}}
</div>
[/js]
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.
[js]
<div ng-repeat=’item in array track by $index’>
</div>
[/js]
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
[js]
<div ng-repeat=’item in getArray()’></div> <!– Don’t use this –>
[/js]
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.
[js]
<div ng-repeat=’item in ::array’>
{{::item.name}} — {{::item.date}}
</div>
[/js]
Your Custom Watchers
If you are using custom watchers in your application, then you stop watches by calling their return function. As seen below.
[js]
var watcher = $scope.$watch(‘variable’,function(newVal,oldVal){
});
$scope.stop = function(){
watcher();
};
[/js]
Here is the full code for this