performance - Angularjs - 优化 ngrepeat 的观察者以仅观察集合的某些属性

标签 performance angularjs angularjs-ng-repeat

在我的 angularJS 应用程序中,我有一个相当大的对象集合(数组)。我需要在不同的地方绑定(bind)到这个集合(例如显示属性:所包含对象的名称)- 绑定(bind)是必不可少的,因为这些名称可能会改变。

由于正常的 ngRepeat 会通过严格的相等比较来观察整个集合,我担心应用程序速度(我们正在谈论具有数千个或更多属性的对象)——我实际上只需要观察集合中的一般变化(比如长度,在翻转两个元素的情况下更改单个引用以及一些特定属性,如提到的 .name 属性)

我正在考虑使用以下方法(基本上创建集合的自定义副本并手动绑定(bind)到原始集合。

我的问题: 所描述的方法是否比观察原始集合更好(通过相等 - 正如我对 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>

任何帮助/意见将不胜感激 - 请注意,我试图创建一个 fiddle 来演示我的方法但失败了:-(

(我知道基准测试可能是测试我的方法的可能解决方案,但我更想知道这里的 angularjs 专业人士的意见)

谢谢, 马蒂亚斯

最佳答案

我想你要找的是 bindonce ,这是一个高性能的绑定(bind)指令,让您可以在 AngularJS 中绑定(bind)一次属性或表达式,正如其名称所暗示的那样。

关于performance - Angularjs - 优化 ngrepeat 的观察者以仅观察集合的某些属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22916020/

相关文章:

javascript - Angular ng-repeat - 跨多个循环的唯一 $index

JavaScript 性能 - .test() 与 .search()

java - 长时间在 MySql 中 hibernate 连接导致 Hibernate 中的进程缓慢

java - 实行预约系统

python - numpy 与 native Python - 最有效的方式

javascript - 动态指令 : templateUrl

javascript - Fullpage JS,分页执行

javascript - 在 javascript/angularjs 中获取客户端 IP

angularjs - 有没有办法只在模板中评估一次 AngularJS 表达式(即没有数据绑定(bind))?

javascript - Angular JS 中的 $http.get API