Angular.js缓存$编译模板/在ng-repeat内呈现指令的性能

时间:2014-03-25 15:38:50

标签: javascript performance angularjs compilation angularjs-directive

我有一个渲染表格单元格的指令(请参阅我在这里编译它的方式,基本上使用$compile Angular.js directive template using variable from parent/inherited scope内部的link fn),现在这个用于两个{ {1}} s,一个用于行,一个用于列,所以它基本上是

ng-repeat

有50行和8列,它对(渲染)性能的影响相当大(非常明显)。

所以我一直在寻找改善它的方法。首先,我试图摆脱列的内部重复,创建一个<ng-repeat row in rows> <ng-repeat column in columns> <my-cell-directive /> </ng-repeat> </ng-repeat> ,它在内部迭代列,找到它们的模板,创建一个字符串(里面有8列),然后编译它。其中将编译量从400降低到50.但它在渲染方面并没有明显改善(确实如此,但只有约15%)。

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

有可能以某种方式吗?或者还有其他方法可以提高渲染速度吗?

2 个答案:

答案 0 :(得分:11)

如果可能,您应该避免在链接功能中使用$compile。您可以缓存$compile的parital结果。

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

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

example

答案 1 :(得分:4)

扩展@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>

...

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