繁体   English   中英

改善Angular中的ng-repeat(只读html表)渲染性能

[英]improve ng-repeat (read only html table) rendering performance in Angular

我已经阅读了六篇有关使用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秒

添加了“ 绑定一次”属性(自angular 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秒。.因此我很可能在这里错过了一些明显的东西。

我想使渲染时间小于1秒。

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

更新我根据这篇帖子添加了一个值班计数器。 结果如下:使用4400行和ng-repeat方法,使用tr pm-table-row方法的观察者为26,102,有4457个观察者,最后使用pm-table-body方法的观察者为57! 有趣的是,这是迄今为止性能最慢的方法。

在进一步剖析pm-table-body方法之后,有趣地进行更新似乎使用了许多角度动画特征。 在此处输入图片说明

禁用动画后, (程序)需要 10秒 在此处输入图片说明

因此,浏览器在很长一段时间内仍无响应,仍在对那里发生的问题进行故障排除。

如果您想提高渲染性能,则应使用limitTo过滤并在页面上实现分页,另一种方法是使用此ngInfiniteScroll 指令在一页上查看整个表。

而且,如果您想在此表中进行某种搜索,则另一个过滤器ng-repeat =“ items | filter:searchString”将应用于整个数据集,不仅应用于您的受限视图,而且您需要请注意, filterfilter器应该在limitTo之前先limitTo ,这样才能起作用。

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

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

有两件事可能会有所帮助:

我知道您说过您可以track by $index进行track by $index因为您已重复测试的条目,但是如果f具有唯一的属性(如ID),它将加快性能以track by f.id进行track by f.id

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

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

最后,一般而言,这只是角度上的缺点,跨大集合重复ng效果不佳。 您可能只需要在ng-repeat之外完全渲染表(特别是如果将它绑定一次,则不需要ng-repeating提供的大量动态功能),或者实现分页或无限滚动。

我花了很多时间在uigrid,表和ngrepeat之间来回切换,甚至用ngrepeat编写了自己的虚拟容器版本。 最后,我决定使用uigrid并使用自定义的行和单元格模板来使其正常运行并按照我的需要进行显示。 uiGrid的好处是它的虚拟化,多列排序和过滤。 我几乎可以即时响应滚动,过滤和排序5k +行(这包括我所有的自定义行和单元格渲染)。 Uigrid还具有无限滚动功能,该功能可以在滚动过程中根据需要从后端动态获取数据,这是我要解决的。 它应该提供一点性能上的好处。

我用uigrid看到的唯一缺点是学习曲线。

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

我也讨厌分页,在非分页解决方案中进行了大量工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM