在Angular

时间:2015-05-13 15:49:37

标签: javascript angularjs performance angularjs-directive

我已经阅读了六篇关于使用ng-repeat提高性能的文章,到目前为止,我无法找到改进简单绑定一次表的渲染的直接方法。

我已经描述了各种方法,到目前为止,我能做的最好的是〜4400行的5秒渲染时间。

**关于此测试用例的说明。我正在使用更大的数据集将性能测试推向具有挑战性的数据集。通常表格为1000行或更少。我希望避免分页,因为在许多情况下,所有数据都可用于扫描异常。更重要的是,300行的渲染时间对我来说也是不可接受的,因为它会在短时间内冻结浏览器,这就是我想要消除的内容。我充分意识到渲染较少的数据会更快,我期待最大化数据集的性能。

我的初步方法

<tbody>
    <tr ng-repeat="f in vm.rowDetails">
        <td class="checkbox-column"><input type="checkbox" ng-model="f.selected" /></td>
        <td class="w100">{{f.Code}}</td>
        <td class="w50">{{f.Class}}</td>
        <td>{{f.WebName}}</td>
        <td>{{f.Category}}</td>
        <td>{{f.MktgCode}}</td>
    </tr>
</tbody>

渲染~7秒

添加了一次绑定属性(从角度1.3开始可用)(尽管它不适用于ng-repeat指令

<tbody>
        <tr ng-repeat="f in vm.rowDetails">
            <td class="checkbox-column"><input type="checkbox" ng-model="f.selected" /></td>
            <td class="w100">{{::f.Code}}</td>
            <td class="w50">{{::f.Class}}</td>
            <td>{{::f.WebName}}</td>
            <td>{{::f.Category}}</td>
            <td>{{::f.MktgCode}}</td>
        </tr>
    </tbody>

没有明显的改善。我认为这有点预期,因为这可以优化后续的观察周期。

开始尝试自己进行行字符串连接。

<tbody>
    <tr pm-table-row f="f" ng-repeat="f in vm.rowDetails track by $index"></tr>
</tbody>

指令:

angular.module('app').directive('pmTableRow', ['$interpolate', function ($interpolate) {
    var template2 = '' +
        '<td class="checkbox-column"><input type="checkbox" ng-model="f.selected" /></td> ' +
                        '<td class="w100">Code</td>' +
                        '<td class="w50">Class</td>' +
                        '<td>WebName</td>' +
                        '<td>Category</td>' +
                        '<td>MktgCode</td>';
    return {
        restrict: 'A',
        replace: false,
        scope: { f: '=' },
        link: function ($scope, $element, $attr) {
            var fields = ['Code', 'Class', 'WebName', 'Category', 'MktgCode'];
            var t = template2;
            var f = $scope.f;
            for (var k in fields)
                t = t.replace(fields[k], f[fields[k]]);

            $element.html(t);
        }
    }}]);

这似乎是一种改进,但不是一个巨大的......渲染下降到~4.7秒

最后我尝试完全删除ng-repeat,并在我的指令

中生成tBody字符串
<tbody pm-table-body items="vm.rowDetails">

指令:

angular.module('app').directive('pmTableBody', ['$interpolate', function ($interpolate) {
    var template2 = '' +
        '<tr><td class="checkbox-column"><input type="checkbox" ng-model="f.selected" /></td> ' +
                        '<td class="w100">Code</td>' +
                        '<td class="w50">Class</td>' +
                        '<td>WebName</td>' +
                        '<td>Category</td>' +
                        '<td>MktgCode</td></tr>';
    return {
        restrict: 'A',
        replace: false,
        scope: { items: '=' },
        link: function ($scope, $element, $attr) {
            var fields = ['Code', 'Class', 'WebName', 'Category', 'MktgCode'];
            var lines = [];

            $scope.$watch('items', function () {
                var items = $scope.items;
                var t1 = new Date();
                var t = template2;
                for (var i = 0; i < items.length; i++) {
                    var f = items[i];
                    for (var k in fields) {
                        t = t.replace(fields[k], f[fields[k]]);
                        lines.push(t);
                    }
                }
                console.log('pmTableBody html concatenation done in: ', (new Date() - t1)/1000); // done in 0.02 seconds 
                $element.html(lines.join(''));
            });
        }
    }}]);

出于某种原因,这使渲染时间增加到28秒..所以我可能会遗漏一些明显的东西。

我想把渲染时间带到&lt; 1秒。

更新我通过在复制的对象上创建唯一的ID字段来删除$ index的跟踪。到目前为止,没有明显的性能变化,但我会继续努力。

更新 我已根据this post添加了一个手表计数器。以下是结果: 有4400行和ng-repeat方法,有26,102名观察者 使用tr pm-table-row方法,有4457名观察者,最后采用pm-table-body方法,有57名观察者!有趣的是,这是迄今为止表现最慢的方法。

更新 有趣的是,在进一步剖析后,pm-table-body方法似乎使用了许多角度动画特征。 enter image description here

禁用动画后,(程序)需要10秒 enter image description here

所以浏览器在很长一段时间内仍然没有响应,仍在排除那里发生的事情。

4 个答案:

答案 0 :(得分:0)

如果您想提高渲染性能,则应使用=RIGHT(F3;LEN(F3)-FIND("=";F3)-1) 过滤器并在页面上实现分页,另一种方法是使用此ngInfiniteScroll directive在一个页面上查看整个表格。< / p>

如果你想知道这个表中的某种搜索,另一个过滤器ng-repeat =“item in:filter:searchString”中的项目将应用于整个数据集,不仅仅是你的有限视图,而是你需要注意的是limitTo过滤器应该在filter之前首先使用过滤器。

答案 1 :(得分:0)

尝试在ng-repeat指令中添加绑定一次属性:

<tr ng-repeat="f in ::vm.rowDetails track by $index">

答案 2 :(得分:0)

可能有所帮助的一些事情:

我知道您说track by $index因为您复制了测试条目,但如果f具有唯一属性(如ID),则会加快track by f.id的性能

如果您正在使用ngAnimate,则禁用它可以缩短渲染时间。

http://ui-grid.info/只对视口中的渲染项执行某些操作,因此您仍然可以将它们全部放在同一个列表中,但只会呈现您当前可以看到的内容。 uigrid有一些缺点。

最后,一般来说,这只是角度的一个缺点,大型集合中的重复次数不是很有效。你可能只需要完全在ng-repeat之外渲染表(特别是如果这是一次绑定,你不需要很多动态功能 - 重复给你),或者实现分页或无限滚动。 / p>

答案 3 :(得分:0)

我花了很多时间在uigrid,桌子,ngrepeat之间来回翻转甚至用ngrepeat编写我自己版本的虚拟化容器。最后,我选择了uigrid和自定义行&amp;细胞模板让它发挥作用,并准确显示我需要它。 uiGrid的好处是它的虚拟化,多列排序和过滤。我可以滚动,过滤和放大排序5k +行几乎是瞬时响应(这包括我所有的自定义行和单元格渲染)。 Uigrid还具有无限滚动功能,在滚动期间根据需要动态地从后端获取数据,我即将解决这个问题。它应该提供轻微的性能优势。

我在uigrid看到的唯一的退缩是学习曲线。

你应该看看的另一个网格是https://github.com/openfin/fin-hypergrid。在我进行的一些快速测试中,这个网格似乎优于uiGrid,我会认真考虑切换,但是我和UIgrid一起做得太过分了。

我也讨厌分页,很多工作都进入了非分页解决方案。