2016-10-04 22 views
8

我想要动态创建使用javascript的角度组件,然后使用$compile使用新创建的作用域进行角度编译。然后,当我不再使用该组件时,我想销毁组件和新范围。

一切都按预期工作,除了这个事实,即使我摧毁新范围,它使用的所有内存都不会被释放。

下面是该代码的简化版本的一部分:

这段代码的
app.controller("mainCtrl", ["$scope", "$compile", function($scope, $compile) { 
    var childScope; 

    //call this every time the button is clicked 
    this.createDirective = function() { 
     //dynamically create a new instance of the custom directive 
     var customDirective = document.createElement("custom-directive"); 

     //if another child scope exists, destroy it 
     if (childScope) { 
      childScope.$destroy(); 
      childScope = undefined; 
     } 

     //create a new child scope 
     childScope = $scope.$new(); 

     //compile the custom directive 
     $compile(customDirective)(childScope); 
    }; 

}]); 

全部工作的例子是here

所有这些代码所做的,就是创建一个新的组件每一个按钮被点击时,但首先销毁已经存在的任何组件。 请注意,我实际上并没有在页面中添加已编译的组件,因为我注意到泄漏仍然存在,无论我是否使用它。

使用Chrome的开发工具(配置文件 - >录制分配时间轴 - >启动),我看到下面的内存使用情况单击按钮 几次后:

Memory consumption

显然,任何占用内存由customDirective决不会实际发布,即使范例的$destroy函数被调用。

我已经在过去成功地使用了$compile而没有创建新的作用域,但似乎我在这种情况下丢失了一些东西。我是否还应该做其他事情以确保没有对新范围的引用?

编辑

基于低于JoelCDoyle答案,这里是修复(我添加的破坏功能,我创建范围):

app.controller("mainCtrl", ["$scope", "$compile", function($scope, $compile) { 
    var childScope; 

    //call this every time the button is clicked 
    this.createDirective = function() { 
     //dynamically create a new instance of the custom directive 
     var customDirective = document.createElement("custom-directive"); 

     //if another child scope exists, destroy it 
     if (childScope) { 
      childScope.$destroy(); 
      childScope = undefined; 
     } 

     //create a new child scope 
     childScope = $scope.$new(); 

     //compile the custom directive 
     var compiledElement = $compile(customDirective)(childScope); 

     //FIX: remove the angular element 
     childScope.$on("$destroy", function() { 
      compiledElement.remove(); 
     }); 
    }; 
}]); 

Fixed fiddle

回答

2

我想我已经找到了解决这个:https://jsfiddle.net/yqw1dk0w/8/

app.directive('customDirective', function(){ 
    return { 
    template: '<div ng-controller="customDirectiveCtrl"></div>', 
    link: function(scope, element) { 
     scope.$on('$destroy', function() { 
     element.remove(); 
     }); 
    } 
    }; 
}); 

我仍然在为什么这个工作有点模糊,但是本节,如何指令编译,在角度编译文档提供了一个线索:https://docs.angularjs.org/guide/compiler

$通过调用前面步骤的组合 逻辑函数编译链接与范围的模板。这反过来将调用单个指令的 连接功能,注册监听器上的元素 并建立$每个 指令配置做的范围对表。\

这样做的结果是在范围和DOM之间进行实时绑定。因此,在这一点上,编译范围中的模型更改将反映在DOM中。

销毁范围,我猜测,不会删除这些元素侦听器。这就是上面的代码所做的:destroy directive/child scope on scope destroy

+0

这确实看起来非常有希望,因为它修复了小提琴的例子。我会将它应用到我的应用程序中,看看它是否也能在那里工作 – kapoiosKapou

+1

是的!这也适用于我更复杂的应用程序..! 虽然..我仍然不完全明白*为什么这个工程。我没有将它添加到DOM中,为什么它需要被删除? 另外,即使当我将编译的元素添加到DOM然后删除它,内存仍然泄漏。 $ compile是否在其他地方添加了这个?就像一个缓存..? – kapoiosKapou

1

它将开始如果将阵列放到示波器并取消分配,则释放分配

$scope.array.length = 0; 

到destcructor。但是...很高兴知道。我将不得不密切关注内存消耗。似乎保留范围。原因我只是取消分配内部变量。

+0

'this.array'在destroy侦听器内部是未定义的(使用'var'而不是'this'设置数组),但方法很有用。垃圾回收回收内存。太好了! –

+0

啊......真的,我把它重新分配到可以释放的范围。编辑... –

+0

这只是照顾症状,它并没有真正解决问题。 该数组仅用于模拟更复杂的组件使用的内存,该组件无法手动删除它正在使用的所有变量 – kapoiosKapou