简体   繁体   English

角度性能:关键渲染路径?

[英]angular performance: critical rendering path?

Im trying to optimice the page loading speed when rendering tables with many rows(columns min. 25x). 我试图在渲染具有许多行的表时(页面最小25x)优化页面加载速度。

I am not experienced debugging/improving performance on angular apps so quite lost on what could be involved in this lack of speed. 我没有经验调试/提高角度应用程序的性能,因此在这种速度不足的情况下可能会失败。

Here is Chrome timeline report for 5 row query: 以下是针对5行查询的Chrome时间线报告:

在此输入图像描述

Here is Chrome timeline report for 100 row query: 以下是针对100行查询的Chrome时间线报告:

在此输入图像描述

The XHR load(api/list/json/Chemical...) increases in time as more rows are rendered on the table. 随着在表上呈现更多行,XHR加载(api / list / json / Chemical ...)会随着时间的推移而增加。

The server response with the data is returned fast(not the bottle neck): 快速返回服务器对数据的响应(不是瓶颈):

Here is the template for the table: 这是表格的模板:

            <tbody ng-if="compressed">
              <tr ng-if="dbos && (rows.length == 0)">
                <td class="tableColumnsDocs"><div class="tableButtons">&nbsp;</div></td>
                <td class="tableColumnsDocs"><div>No results</div></td>
                <td class="tableColumnsDocs" ng-repeat="attobj in columns track by $index" ng-if="$index > 0">
                  <p>&nbsp;</p>
                </td>
              </tr>
              <tr class="tableRowsDocs" ng-repeat="dbo in rows track by $index">
                <td class="tableColumnsDocs"><div ng-include="'link_as_eye_template'"></div></td>
                <td class="tableColumnsDocs" ng-repeat="attobj in columns track by $index">
                  <div ng-init="values = dbo.get4(attobj.key); key = attobj.key; template = attobj.template || getAttributeTemplate(dbo.clazz + attobj.key);">

                    <div class="content" ng-include="template"></div>
                    <div class="contentFiller" ng-include="template"></div>
                  </div>
                </td>
              </tr>           
            </tbody>

And here templates the table will call: 这里的模板会调用:

<script type="text/ng-template" id="plain_values_template">
      <p ng-repeat="v in values track by $index">{{ v }}</p>
</script>

<script type="text/ng-template" id="links_as_dns_template">
      <div ng-repeat="dbo in values track by $index" ng-include="'link_as_dn_template'"></div>
</script>

<script type="text/ng-template" id="json_doc_template">
  <textarea class="form-control" rows="{{values.length + 2}}" ng-trim="false" ng-readonly="true">{{ values | json }}</textarea>
</script>

<script type="text/ng-template" id="link_as_dn_template">
  <a href="#/view/{{ dbo.cid }}"><p>{{ dbo.displayName() }}</p></a>

Relevant controller part: 相关控制器部分:

      $scope.getAttributeTemplate = function(str) {
    //console.log("getAttributeTemplate"); console.log(str);
    if ($templateCache.get(str + ".template")) {
      return str + ".template";
    }
    var a = str.split(/(>|<)/);
    //console.log(a);
    if ((a.length - 1) % 4 == 0) {
      return "links_as_dns_template";
    }
    var clsname = a[a.length - 3];
    if (clsname == "*") {
      return "plain_values_template";
    }
    var attname = a[a.length - 1];
    var cls = datamodel.classes[clsname];
    var att = cls.attribute[attname];
    if (!att) {
      return "plain_values_template";
    }
    if (att.type == "ref") {
      return "links_as_dns_template";
    }
    return "plain_values_template";
  };

在此输入图像描述

I am new to angular and performance opt. 我是角度和性能选择的新手。 so any tips on how to improove or bad practice highlight will be very helpful! 所以任何有关如何改进或不良练习突出显示的提示都会非常有用!

Long tables are angular's biggest evil, because of the hell-as-slow base directives such as ng-repeat 长桌是角度最大的邪恶,因为像ng-repeat这样的地狱般缓慢的基础指令

Some easy and obvious stuffs : 一些简单明了的东西:

I see a lot of bindings in the row/cell templates without one-time binding (::). 我在行/单元格模板中看到很多绑定而没有一次性绑定(::)。 I dont think your row data is mutating. 我不认为你的行数据是变异的。 switching to one-time bindings will reduce the watchers count -> perf. 切换到一次性绑定将减少观察者数量 - >性能。

Some harder stuff : 一些更难的东西:

Quick answer : 快速回答 :

dont let angular handle the performance bottleneck 不要让角度处理性能瓶颈

Long answer : 答案很长:

ng-repeat is supposed to compile it's transcluded content once. ng-repeat应该编译它的被转换内容一次。 But using ng-include is killing this effet, causing every row to call compile on their ng-included contents. 但是使用ng-include会消除这个效果,导致每一行都在其包含ng的内容上调用编译。 The key for good performance in big table is to be able to generates (yea, manually, which $compile, $interpolate and stuff) a unique compiled row linking function, with less as possible angular directives - ideally only one-time expression bindings, and to handle row addiction/removal manually (no ng-repeat, you own directive, your own logic) 在大表中获得良好性能的关键是能够生成(是,手动,$ compile,$ interpolate和stuff)一个独特的编译行链接​​函数,尽可能少的角度指令 - 理想情况下只有一次表达式绑定,并手动处理行成瘾/删除(没有ng-repeat,你自己的指令,你自己的逻辑)

You should AT LEAST find a way to avoid the second nested ng-repeat on' ng-repeat="attobj in columns track by $index"'. 你应该至少找到一种方法来避免第二次嵌套的ng-repeat在'ng-repeat =“attobj in columns track by $ index”'。 This is a dual repeated on each row, killing compilation &linking (rendering perf) and watcher count (lifecycle perf) 这是每一行的双重重复,导致编译和链接(渲染性能)和观察者数量(生命周期性能)

EDIT : as asked, a "naive" example of what can be done to handle the table rendering as manually (and fast) as possible. 编辑:正如所问,一个“天真”的例子,说明如何尽可能手动(和快速)处理表格渲染。 Note that the example does not handle generating the table header, but it's usually not the hardest thing. 请注意,该示例不处理生成表头,但通常不是最困难的事情。

function myCustomRowCompiler(columns) {

    var getCellTemplate = function(attribute) {
        // this is tricky as i dont know what your "getAttributeTemplate" method does, but it should be able to return
        // the cell template AS HTML -> you maybe would need to load them before, as getting them from your server is async.

        // but for example, the naive example to display given attribute would be
        return $('<span>').text("{{::model."+ attribute +"}}"); // this is NOT interpolated yet
    };


    var myRowTemplate = $('<tr class="tableRowsDocs">');

    // we construct, column per column, the cells of the template row
    _.each(columns, function(colAttribute, cellIdx) {
        var cell = $("<td>");
        cell.html(getCellTemplate());
        cell.appendTo(myRowTemplate);
    })

    return $compile(myRowTemplate); // this returns the linking function
}

and the naive usage : 和天真的用法:

function renderTableRows(dbos, columns) {

    var $scope; // this would be the scope of your TABLE directive
    var tableElement = $el; // this would be your table CONTENT

    var rowLinker = myCustomRowCompiler(columns); // note : in real life, you would compile this ONCE, but every time you add rows.


    for(var i=0; i<dbos; i++) {
        var rowScope = $scope.$new(); // creating a scope for each row
        rowScope.model = dbos[0]; // injecting the data model to the row scope
        rowLinker(rowScope, function(rowClone) { // note : you HAVE to use the linking function second parameter, else it will not clone the element and always use the template
            rowClone.appendTo(tableElement);
        });
    }

};

This is the approach i've been using to my own projects's table framework (well, more advanced, but this is really the global idea), allowing to use angular power to render the cell content ( 'getCellTemplate' implementation can return html with directive, which will be compiled), using filter even including directives in the cell, but keeping the table rendering logic to myself, to avoid useless ng-repeat watch, and minimizing the compilation overheat to it's minimum. 这是我一直用于我自己项目的表框架的方法(嗯,更高级,但这确实是全局的想法),允许使用角度功率来呈现单元格内容('getCellTemplate'实现可以返回带有指令的html ,将被编译),使用过滤器甚至包括单元格中的指令,但保持表格渲染逻辑给自己,以避免无用的重复观看,并最大限度地减少编译过热到最小。

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

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