在Angular中手动编译指令时内存泄漏

时间:2014-06-24 16:54:06

标签: jquery angularjs memory-leaks angularjs-directive

我正在尝试手动编译指令并通过JQuery将其添加到DOM中。该指令是一个带有ngClick处理程序的简单div。指令本身没有使用JQuery插件(这似乎是许多其他内存泄漏线程的焦点)。

如果您运行探查器,您会发现它泄漏了节点。有没有什么可以解决这个问题或者它是JQuery / Angular中的问题?

Fiddle here
Profiler screenshot

HTML

<div ng-app="TestApp">
    <buttons></buttons>
    <div id="container"></div>
</div>

的Javascript

var ButtonsCtrl = function($scope, $compile) {
    this.scope = $scope;
    this.compile = $compile;
};

ButtonsCtrl.prototype.toggle = function() {
    var c = angular.element('#container').children();

    if (0 in c && c[0]) {
        c.scope().$destroy();
        c.remove();
    } else {
        var s = this.scope.$new();
        this.compile('<thing color="blue"></thing>')(s).appendTo('#container');
    }
};

var ThingCtrl = function($scope) {};
ThingCtrl.prototype.clicky = function() {
    alert('test');
};

var module = angular.module('components', []);
module.directive('buttons', function() {
    return {
        restrict: 'E',
        template: '<button ng-click="ctrl.toggle()">toggle</button>',
        controller: ButtonsCtrl,
        controllerAs: 'ctrl'
    }
});

module.directive('thing', function() {
    return {
        restrict: 'E',
        scope: {
            color: '@'
        },
        template: '<div style="width:50px;height:50px;background:{{color}};" ng-click="ctrl.clicky()"></div>',
        controller: ThingCtrl,
        controllerAs: 'ctrl'
    };
});

angular.module('TestApp', ['components']);

1 个答案:

答案 0 :(得分:0)

如果你缓存$ compile返回的模板函数,然后使用新范围调用它,内存泄漏似乎减少到每次点击只有一个节点。

var ButtonsCtrl = function($scope, $compile) {
    this.scope = $scope;
    this.makeThing = $compile('<thing color="blue"></thing>');
    this.thingScope = null;
};

此外,从ButtonsCtrl.toggle()方法中删除jQuery包装似乎可以完全消除节点泄漏。

ButtonsCtrl.prototype.toggle = function() {
    var container = document.getElementById('container');

    if (this.thingScope) {
        container.removeChild(container.childNodes[0]);
        this.thingScope.$destroy();
        this.thingScope = null;
    } else {
        this.thingScope = this.scope.$new();
        container.appendChild(this.makeThing(this.thingScope)[0]);
    }
};

See what you think.