【问题标题】:Angular DataTables Directive memory leak when using $compile使用 $compile 时 Angular DataTables 指令内存泄漏
【发布时间】:2014-07-18 04:35:06
【问题描述】:

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

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

如果我注释掉这个方法,那么我看不到泄漏。 rowCompiler 方法获取第一列并将 ID 替换为 id。这个专栏有两个指令,所以我需要使用 $compile 让 Angular 知道这些指令。我尝试过使用 scope.$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>'
}

}])

【问题讨论】:

  • 让我们看看 nRow 的 HTML 和两个指令的代码
  • 我已经添加了渲染的 Html 和指令(它可能甚至不应该是指令),第二个指令是使用引导程序的工具提示指令。

标签: angularjs memory-leaks datatable compilation


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    documentation 说:

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

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

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

    【讨论】:

      【解决方案3】:

      我相信 pixelbits 是在正确的轨道上。我最近submitted 的答案及其随附的 jsfiddle 表明缓存 linking function $compile 返回大大减少了节点泄漏。所以,正如 pixelbits 所说,尝试 $compile 你的模板只一次,然后保存生成的链接函数并在你想要绑定到编译指令的范围上调用它。

      除了前面引用的文档解释编译过程涉及克隆模板元素之外,我无法告诉您关于 Angular 对 $compile 中的节点所做的内部操作,但也许其他问题、答案和小提琴可以指出你在正确的方向。

      【讨论】:

        猜你喜欢
        • 2015-02-12
        • 2017-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-03
        • 2021-09-10
        • 1970-01-01
        相关资源
        最近更新 更多