AngularJS:确定指令渲染所需的时间

时间:2016-09-26 20:14:55

标签: javascript angularjs

如何衡量指令(元素)渲染的程度? 如果没有,是否可以确定哪个指令花费最多的时间进行渲染?

PS。是的,我使用了Batarang,但它只显示了占用时间最多的监视表达式。是的,我用Google搜索并发现question非常相似,但仍然没有答案。

5 个答案:

答案 0 :(得分:6)

我创建了指令来检查角度视图的渲染时间。 Directive使用简单但有用的 speeder lib - https://github.com/maciejsikora/Speeder。它计算从ms-start渲染到ms-stop渲染的微秒。

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

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

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

使用ng-repeats指令的完整示例: https://jsfiddle.net/maciejsikora/4ud2rLgz/

示例指令在控制器中使用,但也可以在另一个指令中使用。这个解决方案的缺点是我们需要将指令附加到DOM,并在发现问题之后将其从那里删除。当然,好主意是创建提供者并将其配置用于开发和生产环境,因此在生产中不应该运行结果和计时。

答案 1 :(得分:5)

为什么不使用Chrome的时间轴检查器?

您可以在渲染之前开始记录时间轴,然后在状态更改后结束它。 enter image description here

单独渲染指令的时间线将是紫色的时间,紫色和绘画楔的总和将为您提供从XHR提取完成到模板绘制到屏幕上的总时间。有没有理由说这不准确?

答案 2 :(得分:3)

对于没有任何Promise的指令,我们可以使用另一个指令,它将$ compile其元素,然后在$ compile的回调函数中调用$ timeout而不进行脏检查(第三个参数 - false):

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);
        });
      }
    }
  };
})

对于带有Promises的指令,我们可以再次使用$ timeout来测量它而不进行脏检查,但是在最后一个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'
  };
});

这是我的playground plunker http://plnkr.co/edit/McWOeF7rZ7ZYKnDWafy6?p=preview,注释/取消注释2指令,尝试在 someDir 指令中增加 i

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()
  });
}

尝试200,2000 ......

答案 3 :(得分:1)

老实说,这个问题本身并没有很好的答案,我将在下面解释。这个问题,至少对我来说,似乎更像是达到目的的手段。所以我认为我们需要了解真正问题的核心:

您是否遇到了正在尝试识别的性能问题,或者您只是想通过配置文件来证明某些内容足够快?

不幸的是,知道指令渲染的时间有太多变量,例如:

  • 儿童指令
  • 异步模板加载
  • 布局颠簸

仅举几个大热门人物。此外,所有指令都会添加元素或设置某些类,然后手动控制浏览器本身以呈现布局。一旦控制权被移交,你基本上就不幸了。

修改DOM很快,非常快,取Velosity.js证明JS可以生成比CSS更快更动画的动画,但有限制:

  • 限制DOM元素的数量,不向用户显示数千个表行。
  • 修改元素类样式列表,确实CSS级联,意味着再次呈现所有子元素。为身体增加了一个课程?您的整个页面只是为了再次渲染。
  • 写入DOM然后从DOM中读取属性会强制页面立即确保布局正确,从而强制渲染。很快就做多次,导致布局颠簸(DOM的多个连续强制渲染)。

答案 4 :(得分:0)

我建议使用以下变体

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)' );
         }
     };  

});

第二个日志和第一个日志之间的差异非常类似于渲染指令所花费的时间。