在我的angularJS应用程序中,我有一个相当大的对象的集合(数组)。我需要在不同的地方绑定到这个集合(例如,显示属性:包含的对象的名称) - 绑定是必不可少的,因为这些名称可能会改变。
正常的ngRepeat会通过严格的相等比较来观察整个集合,我关注的是应用程序的速度(我们正在谈论具有属性或更多属性的对象) - 实际上我只需要观察集合中的一般变化(如长度) ,在翻转两个元素的情况下单个引用的更改以及一些特定属性,如提到的.name属性)
我正在考虑使用以下方法(基本上创建集合的自定义副本并手动绑定到原始集合。
我的问题: 所描述的方法比观察原始集合更好(通过相等 - 因为我理解ngRepeater确实如此)或者是否有更好的方法(例如在watch语句中定义某种比较回调以仅检查某些属性的变化, ...)
<script>
function QuickTestController($scope) {
// simulate data from a service
var serviceCollection = [], counter = 0,
generateElement = function() {
var element = { name:'name' + ++counter };
//var element = { name:'name' };
for (var j = 0 ; j < 5 ; j++) element['property' + j] = j;
return element;
};
for (var i = 0 ; i < 5 ; i++) {
serviceCollection.push( generateElement() );
}
// in the view controller we could either bind to the service collection directly (which should internally use a watchCollection and watch every single element for equality)
$scope.viewCollection = serviceCollection;
// watching equality of collection
/*
$scope.$watch('_viewCollectionObserve', function(newValue, oldValue) {
console.log('watch: ', newValue, oldValue);
}, true);
*/
// or we could create our own watchCollection / watch structure and watch only those properties we are interested in
$scope._viewCollectionObserve = serviceCollection;
var viewCollectionManual = [],
rebuildViewCollection = function() {
viewCollectionManual = [];
for (var i = 0, length = serviceCollection.length ; i < length ; i++) {
viewCollectionManual.push( {name:serviceCollection[i].name } );
}
console.log('- rebuildViewCollection - ');
$scope.viewCollection2 = viewCollectionManual;
},
watchCollectionProperties = [],
unregisterWatchCollection = function() {},
rebuildWatchCollectionProperties = function() {
watchCollectionProperties = [];
for (var i = 0, length = serviceCollection.length ; i < length ; i++) {
watchCollectionProperties.push('_viewCollectionObserve[' + i + ']'); // watch for ref changes
watchCollectionProperties.push('_viewCollectionObserve[' + i + '].name'); // watch for changes in specific properties
}
unregisterWatchCollection();
var watchString = '[' + watchCollectionProperties.join(',') + ']';
unregisterWatchCollection = $scope.$watchCollection(watchString, function(newValues, oldValues) {
console.log('watchCollection: ', newValues, oldValues);
rebuildViewCollection();
});
};
$scope.$watch('_viewCollectionObserve.length', function(newValue, oldValue) { // watch add / remove elements to / from collection
console.log('watch / length: ', newValue, oldValue);
rebuildWatchCollectionProperties();
});
// rebuildViewCollection();
rebuildWatchCollectionProperties();
// click handler ---
$scope.changName = function() { serviceCollection[0].name += '1'; };
$scope.changeSomeProperty = function() { serviceCollection[0].property0 += 1; };
$scope.removeElement = function() { serviceCollection.splice(0, 1); };
$scope.addElement = function() { serviceCollection.push( generateElement() ); };
$scope.switchElement = function() {
var temp = serviceCollection[0];
serviceCollection[0] = serviceCollection[1];
serviceCollection[1] = temp;
};
// will of course not react to this (this is desired behaviour!)
$scope.removeCollection = function() { serviceCollection = []; };
}
</script>
<div data-ng-controller="QuickTestController">
<ul>
<li data-ng-repeat="element in viewCollection">{{element.name}} {{element}}</li>
</ul>
<hr>
<ul>
<li data-ng-repeat="element in viewCollection2">{{element.name}} {{element}}</li>
</ul>
<button data-ng-click="changName()">changName</button>
<button data-ng-click="changeSomeProperty()">changeSomeProperty</button>
<button data-ng-click="removeElement()">removeElement</button>
<button data-ng-click="addElement()">addElement</button>
<button data-ng-click="switchElement()">switchElement</button>
<hr>
<button data-ng-click="removeCollection()">removeCollection (see comment)</button>
</div>
任何帮助/意见将不胜感激 - 请注意我试图创建一个小提琴来演示我的方法但失败了:-(
(我知道基准测试可能是测试我的方法的可能解决方案,但我想知道这里的angularjs专业人士的意见)
感谢, 的Matthias
答案 0 :(得分:0)
我认为你正在寻找的是bindonce,这是一个高性能绑定指令,它允许你在AngularJS中绑定一次属性或表达式,就像它的名字所暗示的那样。
答案 1 :(得分:0)
您还可以尝试的一个问题是'track by'表达式。如果您拥有对集合中每个对象唯一的属性,则可以将其传递给重复表达式。
<div ng-repeat="item in items track by item.id"></div>
我认为Angular会在每件商品上看到该属性。所以这应该会提高性能,但我不知道多少。