javascript - 使用 Angular 的 $compile 和新范围时的内存泄漏

标签 javascript angularjs memory memory-leaks

我想使用 javascript 动态创建 Angular 组件,然后使用 $compile 和新创建的范围对它们进行 Angular 编译。然后当我不再使用该组件时,我想销毁该组件和新范围。

一切都按预期工作,除了即使我正在销毁新范围,它使用的所有内存都不会释放。

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

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 的开发工具(Profiles -> Record Allocation Timeline -> Start)点击按钮后我看到以下内存使用情况 几次:

Memory consumption

很明显,customDirective 占用的任何内存都不会真正释放,即使正在调用作用域的 $destroy 函数。

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

编辑

根据 JoelCDoyle 下面的回答,这里是修复方法(我在我创建的作用域中添加了一个 on destroy 函数):

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

最佳答案

我想我已经找到了解决方案: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();
      });
    }
  };
});

我仍然对它的工作原理有点模糊,但是 Angular 编译文档中的指令如何编译这部分提供了一个线索:https://docs.angularjs.org/guide/compiler

$compile links the template with the scope by calling the combined linking function from the previous step. This in turn will call the linking function of the individual directives, registering listeners on the elements and setting up $watchs with the scope as each directive is configured to do.\

The result of this is a live binding between the scope and the DOM. So at this > point, a change in a model on the compiled scope will be reflected in the DOM.

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

关于javascript - 使用 Angular 的 $compile 和新范围时的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39861690/

相关文章:

javascript - (angularjs) 注入(inject) Controller 时获取 'ReferenceError: $scope is not defined'

javascript - 无法将标题标签居中放置在图像上

css - 将 BEM CSS 与 Angular 指令结合使用

javascript - textarea 在文本溢出时扩展一行

angularjs - 除非是数组,否则变量监视不会触发

c++ - 我的 C++ 程序在内存不足时究竟如何终止?

c++ - 速度和内存的比较

java - 确定java内存使用情况

javascript - 将输入字段设置为标签元素的当前值

javascript - Jquery position() 包括 margin