使用$ compile时Angular DataTables指令内存泄漏

时间:2014-05-28 19:32:11

标签: angularjs memory-leaks datatable compilation

使用自定义DataTables指令时,我遇到了大量的内存泄漏。该指令使用Jquery的DataTables插件,并且有一个函数会导致内存泄漏。

var rowCompiler = function(nRow, aData, iDataIndex) {
    nRow = $compile(nRow)(scope);
}

如果我注释掉这种方法,那么我就不会看到泄漏。 rowCompiler方法获取第一列并用ID替换ID。这个列有两个指令,所以我需要使用$ compile让Angular知道这些指令。我已经尝试使用范围。$ on(' $ destroy',function()但节点和内存不断上升。

以下是数据表中呈现的HTML。

  <tr class="ng-scope odd">
<td class=""><ng-menu-drop ng-idr-id="630" class="ng-isolate-scope">
    <div class="menu-drop">
      <li class="dropdown" style="list-style:none;"> <a class="dropdown-toggle"><i class="icon-cog icon-large"></i> </a>
        <ul class="dropdown-menu">
          <li><a href="#/idr/630/profile/view">Profile</a></li>
          <li></li>
          <li> <a href="#/idr/630/documents">Documents</a></li>
          <li><a href="#/idr/630/communication">Communication </a> </li>
          <li><a href="#/idr/630/hierarchy/">Hierarchy </a></li>
        </ul>
      </li>
    </div>
  </ng-menu-drop>
 </td>

  <td class=""><div tooltip-placement="left" tooltip="test" class="ng-scope">test</div></td>

.directive('ngMenuDrop', [ function(scope, elm, attrs) {
return{
    restrict:"E,A",
    scope: {
        ngIdrId: '@'
    },
    link: function (scope, element, attrs) {

    },
    template: '<div class="menu-drop"><li class="dropdown" style="list-style:none;"><a class="dropdown-toggle"><i class="icon-cog icon-large"></i> </a> ' +
   ' <ul  class="dropdown-menu" ><li><a href="#/idr/{{ngIdrId}}/profile/view">Profile</a><li><li><a href="#/idr/{{ngIdrId}}/documents">Documents</a></li><li><a href="#/idr/{{ngIdrId}}/communication">Communication </a></li><li><a href="#/idr/{{ngIdrId}}/hierarchy/">Hierarchy </a></li></ul></li></div>'
}

}])

3 个答案:

答案 0 :(得分:1)

当你调用$ compile时,你需要确保你没有编译已经编译过的元素。这样做可能会导致内存泄漏,当元素被多次编译并且它们的$ watch没有被清理时。

如果您正在编译DOM树的一部分并发现您正在第二次编译它,那么很可能有更好的方法来构建模板。例如,您可以使用angular.element('...')或使用jquery创建模板,而不是依赖于指令定义中的'template'属性。此外,如果您正在重新编译已转换的内容,那么您应该找到一种方法,以便编译发生一次。

答案 1 :(得分:0)

有时节点泄漏是由javascript事件处理程序引起的。在与行元素有关的指令中,查找可能附加的jQuery或jqLit​​e事件侦听器。当行被删除时,需要删除/取消引用这些行。你可以听一下'$ destroy&#39; DOM事件。这与Angular事件(范围。$ on)不同。

documentation说:

  

$ destroy - AngularJS拦截所有jqLit​​e / jQuery的DOM破坏apis,并在被删除的所有DOM节点上触发此事件。这可用于在删除DOM元素之前清除任何第三方绑定。

在事件处理程序中,您可以删除对节点的引用,取消超时和间隔等。

element.on('$destroy', function () {/* cleanup */});

答案 2 :(得分:0)

我相信 pixelbits 是在正确的轨道上。我最近给出了一个答案submitted及其附带的jsfiddle,证明缓存linking function $ compile返回大大减少了节点泄漏。因此,正如 pixelbits 所说的那样,尝试$只编译模板一次,然后保存生成的链接函数,并在要绑定到编译指令的作用域上调用它。

除了先前引用的文档解释编译过程涉及克隆模板元素之外,我不能告诉你很多关于Angular在$ compile中对节点做什么的内部,但也许其他问题,答案和小提琴可以指向你朝着正确的方向前进。