簡體   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