ng-repeat性能优化
在AngularJS中,ng-repeat是一个我们经常用到的内置指令。
一、repeat报错
我们都知道ng-repeat中的数组存在相同的项时,会照成指令的报错。例如:
<div id="box" ng-controller="controller">
<div ng-repeat="a in data">{ { a }}</div>
</div>
app.controller('controller', ['$scope', function($scope) {
$scope.data = ['aaa', 'bbb', 'aaa', 'ddd'];
}]);
浏览器中运行的结果是: 此时我们通过增加track by,就可以避免报错了。将repeat改成:
<div ng-repeat="a in data track by $index">{ { a }}</div>
其实真正的原因是,repeat不允许数据集中存在两个相同Id的数据,对于数字或者字符串等基本数据类型来说,它的id就是它自身的值,而如对象等引用型的数据则不会有这个问题。
二、track by优化
前面的属于一个插曲,后面的才是正文。
ng-repeat循环生成DOM的方式有两种,一是删除所有的DOM,重新生成新的DOM,二是重复利用前面的DOM,不直接删除DOM,而是修改DOM中的内容。 为了监听DOM的移除,增加DOMNodeRemoved的监听事件。
$('#box').on('DOMNodeRemoved', function(event) { // DOM节点被移除时触发
console.log('DOM remove');
});
前面的例子中的数据太简单了,平常我们是不会repeat一个那么简单的变量的。加入我们现在是要循环一个对象数组。修改例子:
<body ng-app="app" ng-controller="controller">
<div id="box">
<div ng-repeat="a in data">{ { a.name }}</div>
</div>
<button type="button" ng-click="changeData()">change Data</button>
</body>
app.controller('controller', ['$scope', function($scope) {
$scope.data = [{
name: 'aaa'
}, {
name: 'aaa'
}, {
name: 'bbb'
}];
$scope.changeData = function() {
$scope.data = [{
name: 'aaa'
}, {
name: 'ccc'
}, {
name: 'bbb'
}];
}
}]);
多增加了个按钮,用来改变数据。点击按钮,页面显示变化,控制台输出:
我们发现repeat下对应的DOM都发生了删除及重新生成的过程。(6是因为还要加上三个注释节点) 一旦repeat的数据过多的话,这样的操作就会过于消耗性能。
修改数据,增加上唯一的标志id。(也可以直接使用$index,自定义id的话,方便改变顺序)
<div ng-repeat="a in data track by a.id">{ { a.name }}</div>
app.controller('controller', ['$scope', function($scope) {
$scope.data = [{
name: 'aaa',
id: 0
}, {
name: 'aaa',
id: 1
}, {
name: 'bbb',
id: 2
}];
$scope.changeData = function() {
$scope.data = [{
name: 'eee',
id: 0
}, {
name: 'fff',
id: 1
}, {
name: 'ggg',
id: 2
}];
}
}]);
此时,点击按钮,我们发现并没有引起DOM的删除及添加,只是简单的数据修改。这样的修改方式要比前面全部删除的方式要高效的多。
其他情况测试:
1、数据减少
$scope.changeData = function() {
$scope.data = [{
name: 'ddd',
id: 0
}, {
name: 'eee',
id: 1
}];
}
减少修改后的数据,此时点击按钮后,只触发了两次DOM remove,也就是只是删除了多余的一个DOM。
2、顺序变化
$scope.changeData = function() {
$scope.data = [{
name: 'ddd',
id: 0
}, {
name: 'eee',
id: 34
}, {
name: 'eee',
id: 54
}];
}
修改后两个数据的id值,点击按钮修改data后,发现还是触发了4次DOM remove事件。也就是repeat按照key值,决定DOM的删除还是重复利用。
三、总结
在使用ng-repeat时,尽量都带上track by,总会对程序性能总是有些优化的。