当组件被销毁时,Angular如何销毁事件处理程序和属性绑定

时间:2017-10-11 12:59:47

标签: angular angular-components

我试图理解Angular Components的破坏过程比我在文档中找到的更详细。我希望有人能够回答以下问题:

在删除此类元素的事件侦听器之前,是否删除了Component模板中元素的属性?

在组件的销毁过程中,何时以及如何解除事件监听器的注销?

是否有更多关于Angular内部删除事件侦听器的过程的信息?

1 个答案:

答案 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或其子级添加了一些事件侦听器。

是否需要明确调用removeEventListnersUsually 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](); <----------------
        }
    }

要了解有关视图和编译的更多信息,请阅读: