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

时间:2015-11-20 11:35:51

标签: javascript html css angularjs performance

我尝试在渲染具有多行(最小25x列)的表时优化页面加载速度。

我没有经验调试/提高角度应用程序的性能,因此在速度不足的情况下可能会失败。

以下是针对5行查询的Chrome时间线报告:

enter image description here

以下是100行查询的Chrome时间线报告:

enter image description here

随着更多行在表格上呈现,XHR加载(api / list / json / Chemical ...)会随着时间的推移而增加。

快速返回服务器对数据的响应(不是瓶颈):

以下是表格的模板:

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

这里的表格会调用:

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

相关控制器部分:

      $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";
  };

enter image description here

我是角度和性能选择的新手。所以任何有关如何改进或不良练习突出显示的提示都会非常有用!

1 个答案:

答案 0 :(得分:3)

长桌是有角度的最大的邪恶,因为像ng-repeat一样慢的基础指令

一些简单而明显的内容:

我在行/单元格模板中看到很多绑定而没有一次性绑定(::)。我不认为你的行数据是变异的。切换到一次性绑定将减少观察者数量 - &gt;逆足

更难的东西:

快速回答:

不要让角度处理性能瓶颈

答案很长:

ng-repeat应该一次编译它的被抄送内容。但是使用ng-include会消除这个效果,导致每一行都在其包含ng的内容上调用编译。在大表中获得良好性能的关键是能够生成(是,手动,$ compile,$ interpolate和stuff)一个独特的编译行链接​​函数,尽可能少的角度指令 - 理想情况下只有一次表达式绑定,并手动处理行成瘾/删除(没有ng-repeat,你自己的指令,你自己的逻辑)

你应该至少找到一种避免第二次嵌套ng-repeat的方法。 ng-repeat =&#34; attobj in columns track by $ index&#34;&#39;。这是每行重复一次,导致编译和链接(渲染性能)和观察者数量(生命周期性能)

编辑:按照要求,一个天真的&#34;尽可能手动(和快速)处理表呈现的示例。请注意,该示例不处理生成表头,但它通常不是最困难的事情。

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
}

和天真的用法:

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);
        });
    }

};

这是我用于自己项目的表格框架的方法(更好,更高级,但这确实是全球性的想法),允许使用角度功率来渲染单元格内容( &#39; getCellTemplate&#39;实现可以返回带有指令的html,它将被编译),使用过滤器甚至包括单元格中的指令,但保持表格渲染逻辑给自己,以避免无用的重复观看,并最小化编译过热到它的最低限度。