最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AngularJS: Determining how much time the directive takes to render - Stack Overflow

programmeradmin1浏览0评论

How can I measure how much a directive (element) takes to render? If not, is it possible to determine what directive take the most time to be rendered?

PS. Yes, I've used Batarang but it only showed watch-expressions that take the most time. An yes, I've googled and found a question that is much alike, still there's no answer there.

How can I measure how much a directive (element) takes to render? If not, is it possible to determine what directive take the most time to be rendered?

PS. Yes, I've used Batarang but it only showed watch-expressions that take the most time. An yes, I've googled and found a question that is much alike, still there's no answer there.

Share Improve this question edited May 23, 2017 at 12:06 CommunityBot 11 silver badge asked Sep 26, 2016 at 20:14 Eugeny89Eugeny89 3,73110 gold badges55 silver badges103 bronze badges 3
  • 3 There is always this – Corporalis Commented Sep 26, 2016 at 20:24
  • what higher level problem are you trying to solve? – charlietfl Commented Sep 26, 2016 at 21:12
  • @charlietfl, I'm having troubles with perfomance and trying to understand what directives cause them – Eugeny89 Commented Sep 26, 2016 at 21:21
Add a comment  | 

5 Answers 5

Reset to default 7

I created directive to check rendering times of angular view. Directive uses simple but useful speeder lib - https://github.com/maciejsikora/Speeder. It count microseconds from ms-start renders to ms-stop renders.

<span ms-perf ms-start='symbol'></span>

...here some actions ng-ifs, repeats etc.

<span ms-perf ms-stop='symbol'></span>

Full example of using directive with ng-repeats: https://jsfiddle.net/maciejsikora/4ud2rLgz/

In example directive is used in controller, but it can be used also in another directive. Minuses of this solution is that we need to append directive to DOM and after finding problem it should be removed from there. Of course good idea would be to create provider and configurate it for development and production enviroment, so in production no results and time counting should run.

Why not just use Chrome's Timeline inspector?

You could start recording the timeline before render, and then end it after the state change.

The timeline for rendering the directive alone would be the time in Purple, and the sum of Purple and Painting wedges would give you the total time from the time that the XHR fetch was completed, till the template is painted onto the screen. Is there a reason why this wouldn't be accurate?

For directives without any Promises we can use another directive which will $compile its element and then call $timeout without dirty check (3rd argument - false) in $compile's callback function:

app.directive('measure', function () {
  return {
    controller: function ($scope, $element, $compile, $timeout, $window) {
      $window.start = new Date().getTime();
      // make sure to compile only once
      if (!$window.done) {
        console.log('STARTING MEASUREMENT');
        $window.done = true;
        $compile($element)($scope, function(clonedElement, scope) {
          var timer = $timeout(function () {
            console.log('ENDING MEASUREMENT: ' + (new Date().getTime() - $window.start) + 'ms');
            $timeout.cancel(timer);
          }, 0, false);
        });
      }
    }
  };
})

for directives with Promises, we can measure it using again $timeout without dirty check but called in then block of last Promise:

app.directive('someOtherDir', function () {
  return {
    template: '<div ng-repeat="item in vm.data"><img ng-src="{{ item.thumbnailUrl }}" title="{{ item.title }}"></div>',
    controller: function ($http, $timeout, $window) {
      console.log('STARTING MEASUREMENT');
      $window.start = new Date().getTime();
      var vm = this;
      $http.get('data.json').then(function (res) {
        vm.data = res.data;
        var timer = $timeout(function () {
          console.log('ENDING MEASUREMENT: ' + (new Date().getTime() - $window.start) + 'ms');
          $timeout.cancel(timer);
        }, 0, false);
      });
    },
    controllerAs: 'vm'
  };
});

here is my playground plunker http://plnkr.co/edit/McWOeF7rZ7ZYKnDWafy6?p=preview, comment / uncomment 2 directives, try to increase i in someDir directive:

for (var i = 0; i < 20; i++) {
  vm.dates.push({
    timestamp: i * 1000 * 60 * 60 * 24,
    label: new Date(i * 1000 * 60 * 60 * 24).toString()
  });
}

try 200, 2000...

Honestly this question in an of itself does not have a good answer and I'll explain more below. This question, at least to me, seems more like a means to an end. So I think we need to get at the heart of the real question:


Are you having performance issues you are trying to identify or are you just trying to profile to prove something is fast enough?


Unfortunately, there is too many variable things to knowing how long a directive takes to render, such as:

  • child directive
  • async template loading
  • layout thrashing

Just to name a few of a big hitters. Also that all the directive does it adds elements or sets some classes, then hands control over the the browser itself to render the layout. Once control has been handed over your are basically out of luck.

Modifying the DOM is fast, very fast, take Velosity.js that proved that JS can produce faster and smother animation than CSS, but there are limits:

  • Limit the number of DOM elements, don't display 10 of thousands of table rows to the user.
  • Modifying an elements class list of styles, do to the fact that CSS cascades, means all child elements are rendered again. Added a class to the body? Your entire page just for rendered again.
  • Writing to the DOM then reading a property from the DOM forces the page to immediately ensure the layout is correct, forcing a render. Do thing multiple times very quickly and you causing layout thrashing (multiple sequential forced renders of the DOM).

I suggest the following variant

myApp.directive('log', function() {

    return {
        controller: function( $scope, $element, $attrs, $transclude ) {
            console.log( Date.now() + ' (dirrective controller)' );

            //some stuff here
        },
        link: function( scope, element, attributes, controller, transcludeFn ) {
             //some stuff here

             console.log( Date.now() + ' (dirrective post-link function)' );
         }
     };  

});

Difference between second log and first log is something very simmilar to time spent to render the directive.

发布评论

评论列表(0)

  1. 暂无评论