Reputation: 3731
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.
Upvotes: 11
Views: 3240
Reputation: 15442
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...
Upvotes: 3
Reputation: 5254
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:
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:
Upvotes: 1
Reputation: 21870
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?
Upvotes: 5
Reputation: 3731
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.
Upvotes: 0
Reputation: 20162
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.
Upvotes: 7