Reputation: 42
I am trying to understand the destruction process of Angular Components a bit more detailed than what I could find in the documentation. I was hoping someone here would be able to answer the following questions:
Are properties on elements in the Component template removed before the event listeners of such elements are removed?
In the destruction process of a Component, when and how does the de-registration of an event listener happen?
Is there any more information available concerning the process of removing event listeners internally in Angular?
Upvotes: 1
Views: 1907
Reputation: 105497
In JavaScript you cannot remove a DOM node per-se. If you have the following DOM tree:
div.children
span
To "destroy" a span you simply need to remove it from the div.children
. If there are no more links pointing to the span
element it will be garbage collected. And the same holds true for objects.
Imagine the following structure in Angular:
ComponentA.nodes
ComponentBElement -> ComponentBClass
Now Angular needs to "destroy" ComponentB
. To do that it simply detaches ComponentBElement
from the parent ComponentA.nodes
. And this is what Angular does, for example, when you execute viewContainerRef.clear()
:
function execRenderNodeAction(...) {
const renderer = view.renderer;
switch (action) {
...
case RenderNodeAction.RemoveChild:
renderer.removeChild(parentNode, renderNode);
break;
Now, suppose Angular added some event listeners to ComponentBElement
or its children.
Is there any need to explicitly call removeEventListners
? Usually no, because once DOM elements are removed the event listeners are garbage collected as well. However, there's a possibility that a reference to the event listener is captured in some async task or an object that continues to live. This prevents the listener and the DOM from being garbage collected. So Angular ensures that event listeners are removed (in v5 it's DomEventsPlugin.removeEventListener method).
When Angular creates a component view it calls 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; <------
}
}
You can see that event is attached using renderer
and then the unsubscription callback (disposable) is stored into view.disposables
. When Angular destroys a view these disposables are executed and event listeners are removed.:
function [destroyView](view) {
...
if (view.disposables) {
for (var i = 0; i < view.disposables.length; i++) {
view.disposables[i](); <----------------
}
}
To learn more about views and compilation read:
Upvotes: 2