Reputation: 676
I am testing the performance of AngularJS in order to decide whether it is suitable for our application or not. In order to measure and compare the speed of DOM creation, I created a JSFiddle example where one can play around with different numbers of items to create.
The objective is to display n random users ordered by their project. There is content based on the type of project and if the user is secret, he should not be displayed at all.
HTML:
<div ng-repeat="user in users | orderBy:'project'" post-repeat-directive
ng-if="user.secretagent == false"
class="user"
ng-class="{male: (user.gender == 'm'), female: (user.gender != 'm')}"
ng-switch="user.project">
<h2>{{user.name}}</h2>
Project: {{user.project}}
<em ng-switch-when="fame">[fame]</em>
<em ng-switch-when="idol">[idol]</em>
</div>
Javascript:
angular.module('AngularBench', [])
.config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}])
.controller("benchmarkController", ['$scope', 'TimeTracker', function($scope, TimeTracker) {
$scope.result = undefined;
$scope.users = [];
$scope.benchmark = function(size) {
TimeTracker.clockStartDate(size);
var users = getUsers(size);
$scope.users = users;
$scope.$watch(
function () { return TimeTracker.getDuration(); },
function(newVal, oldVal) { $scope.result = newVal; },
true
);
};
}])
.factory('TimeTracker', function() {
var start, end, duration;
return {
clockStartDate: function() {
start = Date.now();
},
clockEndDate: function() {
end = Date.now();
duration = (end - start) / 1000;
},
getDuration: function() {
return duration;
}
};
})
.directive('postRepeatDirective', ['$timeout', 'TimeTracker', function($timeout, TimeTracker) {
return function(scope, element, attrs) {
if (scope.$last){
$timeout(function(){
TimeTracker.clockEndDate();
});
}
};
}]);
function getUsers(size) {
var users = [];
for (var i=0; i<size; i++) {
var user = {
name: 'User ' + i,
gender: Math.random() > 0.5 ? 'm' : 'w',
project: Math.random() > 0.25 ? 'fame' : 'idol',
secretagent: Math.random() > 0.95
};
users.push(user);
}
return users;
}
However, I noticed a strong decrease in performance as the amount of items increases. At about 2500 items it really gets too slow.
I know that the common recommendation is to use pagination or auto-scrolling, but this is not about finding an alternative solution to a big list in ngRepeat. Do you have any suggestions in increasing the performance?
Upvotes: 3
Views: 602
Reputation: 5781
If you plan to have an ng-repeat with thousands of items there's no way around the fact that you will have to pay extra attention and optimize each iteration as much as possible.
For instance, the logic for hiding users can be optimized. Instead of using an ng-if you can use a filter to remove the users that shouldn't be displayed:
ng-repeat="user in users | filter:usersFilter | orderBy:'project'"
That way we can remove them much earlier (even before we're sorting the users). This is a lot faster than having to initialize a directive each iteration, especially since ng-if creates a new child scope, which is a bit costly.
The same goes for ng-switch, which also creates its own child scope.
Here's a modified fiddle where the ng-if and ng-switch have been removed: http://jsfiddle.net/2z2e33em/
It produces the same end result, and it's not surprising it's faster since we have now removed two directives. But I think it illustrates how changes like these can have a dramatic effect on performance (the modified fiddle is roughly 3x faster for me).
Upvotes: 1