为什么即使在$ destroy被触发后范围也没有被破坏?

Cod*_*ate 15 javascript jquery angularjs

我做了一个指令,当单击它时,会创建一个使用jQuery附加到正文的对话框.问题是当关闭对话框时,范围永远不会被正确清理.如下图所示167 ChildScopes被保留.这与对话框中包含ng-repeat指令的项目数量相匹配.

在此输入图像描述

我试图在Plnkr上创建一个非常简单的场景版本.令我惊讶的是,实际上,在Plnkr的每个关闭处都移除了范围.因此,即使在$destroy被调用之后,生产中的某些东西也会导致范围保持活跃.

link: ($scope, $element, $attr) ->
  $element.on 'click', () ->
      $scope.$apply () ->
        child = $scope.$new()
        template = """<span ng-controller="ListCtrl">...List dialog things...</span>"""
        compiledTemplate = $compile(template)(child)
        container = containers.createDialogContainer($element)
        container.append(compiledTemplate)

        #cleanup
        $scope.closeWidget = () ->
          container.trigger("container_close")
          return

        container.on "container_close", ()->
          child.$apply () ->
            child.$destroy()
          return
Run Code Online (Sandbox Code Playgroud)

所以这是我的问题:

甚至在$ destroy被调用,触发和执行垃圾收集之后,什么可以导致范围保持活跃?

出于显而易见的原因,我无法向您展示我们的生产代码 但是,Plnkr中的指令与我的调试充分匹配.

Pie*_*len 5

通常,如果GC仍可由另一个JS对象访问,则无法清除作用域(或任何其他JS对象).

实际上,在一个也使用JQuery的Angular项目中,这很可能是由以下原因引起的:

  • 一个Angular服务,控制器,作用域或一些其他对象仍然具有对您的作用域对象的引用
  • 您的对象的引用仍然通过DOM元素存在,可能通过事件侦听器.DOM元素本身可能不是GC,因为它仍然在JQuery的缓存中

例如,您的示例会产生内存泄漏.

从您的代码:

 $scope.removeDialog = () ->
    console.log "closing"
    child.$destroy()
    $('.listshell').remove()
    return
Run Code Online (Sandbox Code Playgroud)

你不设置childnull这样$scope.removeDialog仍然可以访问被引用的范围对象child变量.因此,此对象不能被GC.

注意:在我看来,穿上removeDialog儿童范围会更合适.现在您的示例仅起作用,因为子范围不是孤立的.