使用$ scope。$ destroy解决了内存泄漏问题但违反了指令

时间:2015-12-19 05:12:00

标签: javascript angularjs angular-directive

我有一个在TypeScript AngularJS应用程序中运行非常动态的子指令。模板和控制器在运行时根据给定情况需要执行的操作附加,模板本身包含许多指令。我需要能够在页面上显示多个指令,因此我在每个指针之间使用了一个隔离的范围。我有另一个指令负责跟踪在任何给定时间应该在页面上的哪些子指令(称为父指令)。

如果我需要添加一个新子节点,我在该父节点中为它创建模板,标识我想要附加它的元素并使用:

var compiledDirective = this.$compile(myTemplate)(scope.$new(true, scope));
angular.element(".parent").append(compiledDirective);
_.defer(() => {
  scope.$apply();
});

如果我加载应用程序,这可以正常工作,我可以看到它创建每个运行正如我所期望的那样的子项。当我需要删除任何/所有这些子节点时,此父节点也会在以下函数中处理它:

var destroyChild = (identifier: string) {
  this.$timeout(() => {
    var elem = angular.element(".parent").find(`li[ident='${identifier}']`);
    elem.scope().$destroy();
    elem.remove();
    _.defer(() => {
    });
  });
}

现在,所有元素都按预期移除了自己,如果我看看Batarang,我会看到指令从可用范围中消失。我在child子指令中有一个$ destroy事件的事件处理程序,所以当指令被销毁时我可以看到一个控制台消息,并且在这个destroy函数运行后它会按预期显示。

这里的问题是我需要能够根据父级页面上的其他活动添加更多这些子指令。在这个destroy活动之后,我发现当我第二次重新执行这个过程时,范围没有很好地加载 - 相反,我看到现在为child指令创建了一些范围,但我发现有些绑定不再更新(例如,我注意到当子指令中的范围值发生变化时,ng-hide不再更新),因此该指令最终无法使用。

一般来说,我认为逻辑中只有一个错误而且我需要去寻找它并且可能很好,除了在调试这个时,我发现在那个处理破坏它的父函数中子指令,如果我注释掉这一行:

elem.scope().$destroy();

所有范围都保留在Batarang中,并且所有DOM元素都会像您期望的那样消失,所以这看起来有点像内存泄漏,除非我运行触发器使指令再次加载,它们会加载没有问题(我只是在Batarang视图中结束了许多范围,现在永远不会清除)。

什么会导致这种行为,因为$销毁指令的隔离范围会破坏指令的未来使用,但是留下它会让它在以后工作,但会导致内存泄漏?是否有其他方法可以在不使用$ destroy的情况下清除这些范围?

修改 经过进一步调查,我发现当第一个指令被创建时,它有一个适当创建的隔离范围,但是在制作后续指令时,它们的隔离范围是在Batarang中创建的,但是如果我实际使用angular.element进行查找('lookup-their-individual-idents')。scope()报告的ID实际上是父级的ID,因此当我破坏第一个时,它会按预期清理。当我销毁第二个时,它实际上消灭了父范围(以及所有孩子),所以这就是为什么它没有准确地放在父母的前进。

所以,我希望我只需要弄清楚当我将它们添加到DOM时如何将隔离的范围适当地绑定到指令,其余的将自行解析。

1 个答案:

答案 0 :(得分:4)

一旦我开始关注哪些指令在Batarang中被创建和销毁时,这个问题就变得明显了。如果第一个指令始终具有隔离范围,则后续指令都不会,而且它们都会继承父范围,因此当它们全部被销毁时,父范围将与它们一起使用。

相反,虽然上面显示的代码用于创建页面上没有任何内容的新指令,但我需要更新实际负责在该父指令中将多个指令放在页面上以使其创建的代码每个新孩子的孤立范围,例如:

var child = this.templateGenerator.addChild(applicableData);
var compiledChild = this.$compile(child)(scope.$new(true));
element.append(compiledChild);

现在如果我查看每个指令,他们都指向Batarang的预期范围。更重要的是,当我销毁它们并在页面上放置新指令时,它们也按预期加载,因此这解决了问题。