使用带有新范围的angular的$ compile时内存泄漏

时间:2016-10-04 21:02:52

标签: javascript angularjs memory memory-leaks

我想使用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

很明显,即使调用了作用域的$destroy函数,也不会实际释放customDirective占用的任何内存。

我过去成功使用$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 个答案:

答案 0 :(得分: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

  

$ compile通过调用组合链接模板与范围   链接上一步的功能。这反过来会打电话给   链接各个指令的功能,注册监听器   关于元素并设置$ watchs,范围为每个   指令配置为。\

     

结果是范围和DOM 之间的实时绑定。所以在这个&gt;点,编译范围内模型的变化将反映在DOM中。

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

答案 1 :(得分:1)

如果将数组放入作用域并取消分配

,它将开始解除分配
$scope.array.length = 0;

到destcructor。但是......很高兴知道。我必须仔细观察内存消耗。似乎保留了范围。因为我只是取消分配内部变量。