AngularJS: определение того, сколько времени требуется для выполнения директивы для рендеринга

Как я могу измерить, какую часть директивы (элемента) принимает для рендеринга? Если нет, можно ли определить, какая директива занимает больше всего времени для рендеринга?

PS. Да, я использовал Batarang, но он показывал только часы-выражения, которые занимают больше всего времени. Да, я googled и нашел question, который очень похож, но там нет ответа.

Ответ 1

Я создал директиву для проверки времени рендеринга представления angular. Директива использует простой, но полезный 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-повторами: https://jsfiddle.net/maciejsikora/4ud2rLgz/

В примере директива используется в контроллере, но ее можно использовать и в другой директиве. Недостатки этого решения заключаются в том, что нам нужно добавить директиву в DOM, и после обнаружения проблемы ее следует удалить. Разумеется, хорошей идеей было бы создание провайдера и его настройка для разработки и производства, поэтому в производстве не должно быть результатов и подсчета времени.

Ответ 2

Почему бы просто не использовать инспектор хронологии Chrome?

Вы можете начать запись временной шкалы перед рендерингом, а затем завершить ее после изменения состояния. введите описание изображения здесь

Сроки выполнения только одной директивы были бы временем в Purple, а сумма клинков Purple и Painting дала бы вам общее время с момента завершения XHR-выборки, пока шаблон не будет нарисован на экране. Есть ли причина, почему это не было бы точным?

Ответ 3

Для директив без Promises мы можем использовать другую директиву, которая будет компилировать свой элемент $, а затем вызывать $timeout без грязной проверки (третий аргумент - ложь) в функции компиляции обратного вызова $

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 без грязной проверки, но вызвав затем блок последнего обещания:

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

вот мой плунжер для игровых площадок http://plnkr.co/edit/McWOeF7rZ7ZYKnDWafy6?p=preview, комментировать/раскомментировать 2 директивы, попытаться увеличить я в директиве someDir:

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...

Ответ 4

Честно говоря, этот вопрос сам по себе не имеет хорошего ответа, и я объясню ниже. Этот вопрос, по крайней мере для меня, кажется скорее средством для достижения цели. Поэтому я думаю, что нам нужно понять суть настоящего вопроса:


У вас проблемы с производительностью, которые вы пытаетесь определить, или вы просто пытаетесь профилировать, чтобы доказать, что что-то достаточно быстро?


К сожалению, существует слишком много переменных, чтобы узнать, сколько времени требуется для рендеринга, например:

  • дочерняя директива
  • Загрузка шаблона async
  • разбивка макета

Просто чтобы назвать несколько больших нападающих. Кроме того, что вся директива добавляет элементы или устанавливает некоторые классы, тогда руки управляют самим браузером для рендеринга макета. После того, как управление было передано, вам в основном не повезло.

Модификация DOM выполняется быстро, очень быстро, возьмите Velosity.js, который доказал, что JS может производить быстрее и чем CSS, но существуют ограничения:

  • Ограничьте количество элементов DOM, не показывайте пользователю 10 тысяч строк таблицы.
  • Изменив список стилей классов элементов, сделайте так, чтобы CSS-каскады означали, что все дочерние элементы снова отображаются. Добавлен класс для тела? Вся ваша страница только для рендеринга.
  • Запись в DOM, затем чтение свойства из DOM заставляет страницу немедленно гарантировать правильность компоновки, заставляя рендер. Делайте вещь несколько раз очень быстро, и вы вызываете разметку макета (несколько последовательных принудительных рендерингов DOM).

Ответ 5

Я предлагаю следующий вариант

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

});

Разница между вторым журналом и первым журналом - это что-то очень близкое к времени, затрачиваемому на визуализацию директивы.