【问题标题】:Angular.js caching $compiled templates / rendering performance of directives inside ng-repeatAngular.js 缓存 $compiled 模板/在 ng-repeat 中渲染指令的性能
【发布时间】:2014-03-25 15:38:50
【问题描述】:

我有一个渲染表格单元格的指令(看看我在这里如何编译它,基本上在link fn Angular.js directive template using variable from parent/inherited scope 内使用$compile),现在它在两个ng-repeats 内使用,一个用于行,一列,所以基本上是

<ng-repeat row in rows>
  <ng-repeat column in columns>
    <my-cell-directive />
  </ng-repeat>      
</ng-repeat>

它有 50 行和 8 列,它对(渲染)性能产生了很大的影响(无论如何非常明显)。

所以我一直在寻找改进它的方法。首先,我试图摆脱列的内部重复,创建一个my-cols-directive,它在内部迭代列,找到它们的模板,创建一个字符串(里面有这 8 列),然后编译它。这将编译量从 400 降低到 50。但它并没有真正在渲染方面有明显的改进(确实有,但只有大约 15%)。

现在我的另一个想法是以某种方式将它减少到只有一个编译,基本上在 ng-repeat 的第一次迭代中编译它,然后保存(缓存)编译结果,以便指令然后使用它而不是编译它再一次,只是用当前迭代中的值替换绑定值。

有可能吗?或者有没有其他方法可以提高渲染速度?

【问题讨论】:

  • 渲染/编译一行大约需要 20 毫秒。50 行意味着 1000 秒,这绝对是明显的挂起。

标签: javascript performance angularjs compilation angularjs-directive


【解决方案1】:

如果可能,您应该避免在链接函数中使用$compile。不过,您可以缓存 $compile 的部分结果。

使用compiled对象的第二个参数cloneAttachFn

directive('lol', function($compile){
  var compiled = $compile(template);
  return function(scope, element, attr){
    compiled(scope, function(clonedElement, scope){
      element.append(clonedElement);  
    };
  }
})

example

【讨论】:

  • 问题是我实际上需要范围来获得正确的模板,请参阅另一个问题stackoverflow.com/questions/22617574/…
  • 阅读我创建的示例,您应该对此很熟悉。只需创建多个编译元素,然后选择要在链接函数中使用的元素。
  • 谢谢你!这实际上帮助我解决了使用动态模板选择器使用 ng-repeat 时遇到的问题。这将我的渲染时间从 2.5 秒缩短到了即时!
  • @JaymesBearden,您能否展示一下您的指令的外观?
  • @ironic 我将发布我的解决方案作为另一个答案,或多或少我做了什么
【解决方案2】:

扩展@goofy 的答案并回答@ironic,这是我想出的:

(function (angular) {

var messageSelectorDirective = ['$compile', function ($compile) {
    // Create cached message templates, this could also come from a service or you can use other caching strategies
    var messageTypeTemplates = {
        'TYPE1': $compile('<message-type1 class="message" />'),
        'IMAGE': $compile('<image-message class="message image-message" maybe-another-directive />'),
        'SMS_FOLLOWUP': $compile('<sms-message class="message message-type3" ng-hide="thisCanWorkToo" />'),
        'DEFAULT': $compile('<message-type1 class="message" />')
    };

    // Based on the supplied message.$type property, select an appropriate directive -- returns a default if not found
    function getCompiledMessageTemplate(message) {
        return angular.isDefined(messageTypeTemplates[message.$type]) ? messageTypeTemplates[message.$type] : messageTypeTemplates['DEFAULT'];
    }

    return {
        restrict: 'A',
        scope: {
            $message: '=message',
            $context: '=context'
            // You could also provide a selector function here that determines how to choose a directive from the message, or it could be a service ...
        },
        link: function (scope, element) {
            var template = getCompiledMessageTemplate(scope.$message);
            var templateElement;

            template(scope, function (clonedElement, scope) {
                templateElement = clonedElement;
                element.append(templateElement);
            });

            template = null;

            element.on("$destroy", function () {
                templateElement.remove();
                templateElement = null;
            });
        }
        // You can optionally have a controller here that allows you operate on the supplied context since this is an isolated directive
        // controller: 'MessageSelectorController'
    };
}];

angular.module('directives').directive('messageSelector', messageSelectorDirective);
})(angular);

在 HTML 中的用法:

...

<ol class="list-unstyled">
    <li class="row" message-selector message="::message" context="::context" ng-repeat="message in filteredMessages = (messages | limitLast:renderLimit) track by message.id">
        <!-- 
        In here will be the properly selected directive rendered according the the message.$type. When you receive the data from the server, you can
        decide how to map an individual message in to a given $type which the directive above will use, OR, you can use another strategy for selection!

        Since you have full control over the template selection, you can also decide what things you want to be in an individual message. You have lots of options here!
        -->
    </li>
</ol>

...

希望这可以帮助某人或提供一些想法!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-06
    • 2017-01-04
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    相关资源
    最近更新 更多