使用$scope$destroy解决了内存泄漏,但破坏了指令

Using $scope.$destroy solves memory leak but breaks directive

本文关键字:坏了 指令 泄漏 内存 scope destroy 解决 使用      更新时间:2023-09-26

我有一个在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,我会看到指令从可用范围中消失。我在子指令中有一个$destroy事件的事件处理程序,所以当指令被销毁时,我可以看到一条控制台消息,并且在这个destroy函数运行后,它会按预期显示。

这里的问题是,我需要能够基于父级中页面上的其他活动添加更多的这些子指令。在这个销毁活动之后,我发现当我第二次重新执行这个过程时,作用域加载不太正确——相反,我现在看到了为子指令创建的许多作用域,但我发现一些绑定不再更新(例如,当子指令中的作用域值发生变化时,我注意到ng隐藏不再更新),因此该指令最终不可用。

一般来说,我会假设逻辑中有一个错误,我需要去寻找它,很可能会有,只是在调试时,我发现在处理销毁子指令的父函数中,如果我注释掉这一行:

elem.scope().$destroy();

所有作用域都保留在Batarang中,所有DOM元素都如您所料消失了,所以这看起来有点像内存泄漏,只是如果我运行触发器使指令再次加载,它们加载时不会出现问题(我只是在Bataraang视图中发现了许多作用域,但这些作用域永远不会清除)。

是什么导致了这种行为,因为$破坏指令的隔离作用域会破坏指令的未来使用,但将其留在那里会使其稍后工作,但会导致内存泄漏?有没有其他方法可以在不使用$destroy的情况下清除这些作用域?

编辑:经过进一步的调查,我发现当创建第一个指令时,它有一个适当创建的隔离作用域,但在生成后续指令时,它们的隔离作用区是在巴塔朗中创建的,但如果我真的用angular.element('lookuptheir-individeal-idents').scope()进行查找,则报告的ID实际上是父级的ID,所以当我销毁第一个时,它会像预期的那样清理干净。当我销毁第二个时,它实际上会删除父作用域(从而删除所有子作用域),所以这就是为什么它没有准确地放置在父作用域上的原因。

因此,当我将隔离的作用域添加到DOM时,我希望我只需要弄清楚如何将它们适当地绑定到指令,其余的将自行解决。

当我开始查看哪些指令在巴塔朗中被创建和销毁时,这个问题就变得很明显了。如果第一个指令总是有一个孤立的作用域,那么后面的指令都不会继承父作用域,相反,它们都继承了父作用域。所以当它们都被销毁时,父作用域就会随之而去。

相反,虽然我上面显示的代码用于创建页面上没有的新指令,但我需要更新实际负责在父指令中的页面上放置多个指令的代码,使其为每个新子指令创建独立的范围,例如:

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

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