我试图理解Angular Components的破坏过程比我在文档中找到的更详细。我希望有人能够回答以下问题:
在删除此类元素的事件侦听器之前,是否删除了Component模板中元素的属性?
在组件的销毁过程中,何时以及如何解除事件监听器的注销?
是否有更多关于Angular内部删除事件侦听器的过程的信息?
答案 0 :(得分:2)
在JavaScript中,您无法删除DOM节点本身。如果您有以下DOM树:
div.children
span
To" destroy"你只需要从div.children
删除它。如果没有更多指向span
元素的链接,它将被垃圾收集。对于对象也是如此。
想象一下Angular中的以下结构:
ComponentA.nodes
ComponentBElement -> ComponentBClass
现在Angular需要"销毁" ComponentB
。要做到这一点,只需将ComponentBElement
与父ComponentA.nodes
分开即可。这就是Angular所做的事情,例如,当你执行viewContainerRef.clear()
:
function execRenderNodeAction(...) {
const renderer = view.renderer;
switch (action) {
...
case RenderNodeAction.RemoveChild:
renderer.removeChild(parentNode, renderNode);
break;
现在,假设Angular向ComponentBElement
或其子级添加了一些事件侦听器。
是否需要明确调用removeEventListners
? Usually no,因为一旦移除DOM元素,事件侦听器也会被垃圾收集。但是,有可能在某些异步任务或继续存在的对象中捕获对事件侦听器的引用。这可以防止侦听器和DOM被垃圾回收。因此Angular确保删除事件侦听器(在v5中它是DomEventsPlugin.removeEventListener方法)。
当Angular创建组件视图时,它会调用listenToElementOutputs:
function listenToElementOutputs(view, compView, def, el) {
for (var i = 0; i < def.outputs.length; i++) {
...
var disposable = listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure));
((view.disposables))[def.outputIndex + i] = disposable; <------
}
}
您可以看到使用renderer
附加事件,然后将取消订阅回调(一次性)存储到view.disposables
中。当Angular破坏视图时,会执行这些一次性事件并删除事件侦听器。
function [destroyView](view) {
...
if (view.disposables) {
for (var i = 0; i < view.disposables.length; i++) {
view.disposables[i](); <----------------
}
}
要了解有关视图和编译的更多信息,请阅读: