Rosher Consulting

Software Consulting and Development Services

Angular Tips: Measuring Rendering Performance

Recently I’ve had to try and improve the performance of a page that had too many watches, specifically I had a table where each row was generated with an ‘ng-repeat’ and then within each row I had a ‘select’ element whose options were also generated with an ‘ng-repeat’. The ‘select’ had around 200 options with a binding for both the value and text, the number of rows varied but probably averaged around 5 and each row had a few bindings itself, so tally that up and you’re looking at over 2000 bindings, which when combined with the rest of the page was quite simply too much.

There are many ways of improving the performance of this page but before attempting any changes I wanted to be able to measure the rendering performance, so that I would then have something to compare my changes to.

I’d previously read the blog post from Scalyr on improving Angular rendering performance and in this post they mentioned that they ‘detected the finish of the $digest cycle’ in order to measure the rendering performance. I was curious how they did this and nothing obvious popped up in my searching, however I then noticed a question in the comments, which Scalyr responded to that pointed me in the right direction, I quote:

‘The approach we used was to use a $provider decorator on the $rootScope service to monkey patch $rootScope.$digest. In the override method, we simply record the start time, invoke the original $digest method, and then capture the end time.’

From this I was able to determine that I needed to override the regular ‘$digest’ method and replace it with my own, so I came up with the following simple override:

   1:  angular.module('myApp').run(['$rootScope', function($rootScope) {
   3:              var $oldDigest = $rootScope.$digest;
   4:              var $newDigest = function() {
   5:                  console.time("$digest");
   6:                  $oldDigest.apply($rootScope);
   7:                  console.timeEnd("$digest");
   8:              };
   9:              $rootScope.$digest = $newDigest;
  10:          }])

This will call 'console.time' when the ‘$digest’ starts and 'console.timeEnd' when it finishes, which allowed me to see how long each render of the DOM takes. Combined with some logging in my controller I was then able to see that after my data had been loaded from the server it took around 3-4 seconds to render this to the page and for the page to be ready for input.

With some useful measurements to hand, I could now begin the process of making some improvements.

Comments are closed