【问题标题】:Angular ng-class performance issue when too many elements in DOM当 DOM 中的元素过多时,Angular ng-class 性能问题
【发布时间】:2015-01-13 18:09:29
【问题描述】:

我一直在处理一个导致性能问题的复杂角度页面。为了突出这个问题,我在这里创建了一个小提琴http://jsfiddle.net/4ex2xgL1/3/

本质上,性能问题是由具有函数的 ng-class 语句引起的。

<span class="done-{{todo.done}}" ng-class="myfunction()">{{todo.text}}</span>

跨度在 ng-repeat 中。在运行 fiddle 时,可以看到 ng-class 在页面加载时被执行了几次,并且在每个键上它被调用的次数与 TODO 列表中的项目数一样多。

这是一个简单得多的例子,在我的例子中,我的页面上有 780 个项目,函数最终被评估了大约 3000 次!

我们看到的解决方案之一是拆分范围,但这几乎会导致我的应用程序被重写。

我们也尝试过https://github.com/Pasvaz/bindonce,但它似乎不适用于高度动态的内容。

有什么想法吗?

【问题讨论】:

  • 在实际应用中,myfunction() 的输入是否依赖于ng-repeat 中的当前项?它需要什么样的输入才能产生结果?可能的解决方案将取决于该函数的结果有多动态。
  • 我认为不显示 780 项。仅显示可见项目。在 Google 无限列表中搜索
  • 我想到的另一件事是根本不使用ng-class。而是创建指令,它将根据您的需求更改类(基于用户行为)
  • @ivarni:我们嵌套了 ng-repeat,并且在 ng-class 中有两个条件。如果条件为真,则将调用 myfunction()。在我们使用父母的 ng-repeat 和 myfunction() 的条件下,我们使用了 ng-repeat 子 ng-repeat

标签: javascript html angularjs


【解决方案1】:

我用https://github.com/JimLiu/angular-ui-tree 构建了一棵树,其中有近 500 个要渲染的项目,有很多听众。渲染需要 5 秒。 Bindonce 在那里不起作用。

唯一的解决方案是让 ng-repeat 做的更少。使用分页、搜索或其他方式使列表保持较小。据我所知,这是最好的镜头。

这是我的建议

  1. 在复选框上使用 ng-change 来操作 dom 或任何东西,而不是使用 ng-class,它会大大提高你的性能。

    <li ng-repeat="todo in todos track by todo.id"> <input type="checkbox" ng-model="todo.done" ng-change="myfunction()"> <span class="done-{{todo.done}}">{{todo.text}}</span> </li>

    http://jsfiddle.net/4ex2xgL1/3/

  2. 如果您有 id,请在 ng-repeat 中使用 track by,更多信息请参见 http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/

  3. 不在列表中显示 780 项。使用搜索框显示大约 100 或 50 个,或者您知道得更多

  4. quick-ng-repeat 还没用,试试看https://github.com/allaud/quick-ng-repeat

终于有几个不错的http://tech.small-improvements.com/2013/09/10/angularjs-performance-with-large-lists/

【讨论】:

  • 事实上我无法进行分页,我正在制作一个 UI 来处理 32 颗牙齿并为每颗牙齿显示大约 20 个项目。业务需求不允许我进行任何分页,因为从 UX 角度来看它是不正确的!我会尝试 ng-change 是否有办法调用 ng-class 。我的意思是只有在用户停止所有活动后才评估 ng-class!
  • 好吧,总有办法的。问题是 angulars ng-attrs 都是观察者,每个观察者都会根据相关数据集的微小变化进行评估。所以这么多的 ng-class 势必会影响性能。但正如我所说,总有办法。你能给我一些项目ui的截图吗?
【解决方案2】:

我终于找到了解决方案,它将有助于提高 Angular js 的性能。

如果您的模型是动态变化的,并且如果您有大量数据,那么它还能将 AngularJS 页面的渲染速度提高 1000% 甚至更多 - 不开玩笑!。

更多信息您可以访问:http://orangevolt.blogspot.in/2013/08/superspeed-your-angularjs-apps.html

按照以下步骤操作:

  1. 从链接下载库:library

2. 没有库的例子:(检查你的控制台)

function MyController( $scope) {
    var entries = [ 
        { label : 'one', value : 'first entry'}, 
        { label : 'two', value : 'second entry'}, 
        { label : 'three', value : 'third entry'}
    ];
    
    $scope.label ="";
    $scope.value ="";
    $scope.order = 'label';
    
    $scope.add = function() {
        entries.push({ 
            label : $scope.label, 
            value : $scope.value
        });
    };
        
    $scope.getEntries = function() {
        console && console.log( "getEntries() called");
        return entries;
    };
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>

<form name="myform" ng-app ng-controller="MyController">
    Label/Value :
    <input type="text" required ng-model="label">
    <input type="text" required ng-model="value">
    <button 
        ng-disabled="!myform.$valid" 
        ng-click="add()"
    >Add</button>
        
    <fieldset>    
        <legend>
            Entries sorted by 
            <select 
                ng-model="order" 
                ng-options="property for property in [ 'label', 'value']">
            </select>
        </legend>
        <div ng-repeat="entry in getEntries() | orderBy:order">
            {{entry.label}} = "{{entry.value}}"
        </div>
    </fieldset>
</form>

3.example with library:(检查你的控制台)

function MyController( $scope) {
    var entries = [ 
        { label : 'one', value : 'first entry'}, 
        { label : 'two', value : 'second entry'}, 
        { label : 'three', value : 'third entry'}
    ];
    
    $scope.label ="";
    $scope.value ="";
    $scope.order = 'label';
    
    $scope.add = function() {
        entries.push({ 
            label : $scope.label, 
            value : $scope.value
        });
            // clear cache
        $scope.getEntries.cache = {};
    };
        
    $scope.getEntries = _.memoize( 
        function() {
            console && console.log( "getEntries() sorted by '" + $scope.order + " 'called");
                // return entries sorted by value of $scope.order
            return _.sortBy( entries, $scope.order);
        }, 
        function() { 
                // return the cache key for the current result to store 
            return $scope.order;
        }
    );
}
<script src="https://raw.githubusercontent.com/lodash/lodash/2.4.1/dist/lodash.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>

<form name="myform" ng-app ng-controller="MyController">
    Label/Value :
    <input type="text" required ng-model="label">
    <input type="text" required ng-model="value">
    <button 
        ng-disabled="!myform.$valid" 
        ng-click="add()"
    >Add</button>
        
    <fieldset>    
        <legend>
            Entries sorted by 
            <select 
                ng-model="order" 
                ng-options="property for property in [ 'label', 'value']">
            </select>
        </legend>
        <div ng-repeat="entry in getEntries()">
            {{entry.label}} = "{{entry.value}}"
        </div>
    </fieldset>
</form>

【讨论】:

    猜你喜欢
    • 2015-03-26
    • 2017-01-20
    • 2011-05-20
    • 1970-01-01
    • 2015-07-10
    • 2013-03-03
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    相关资源
    最近更新 更多