If a DOM Element is removed, are its listeners also removed from memory?
Asked Answered
E

6

440

If a DOM Element is removed, are its listeners removed from memory too?

Emplacement answered 21/9, 2012 at 9:42 Comment(0)
S
388

Modern browsers

Plain JavaScript

If a DOM element which is removed is reference-free (no references pointing to it) then yes - the element itself is picked up by the garbage collector as well as any event handlers/listeners associated with it.

var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
b = null; 
// A reference to 'b' no longer exists 
// Therefore the element and any event listeners attached to it are removed.

However; if there are references that still point to said element, the element and its event listeners are retained in memory.

var a = document.createElement('div');
var b = document.createElement('p'); 
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b); 
// A reference to 'b' still exists 
// Therefore the element and any associated event listeners are still retained.

jQuery

It would be fair to assume that the relevant methods in jQuery (such as remove()) would function in the exact same way (considering remove() was written using removeChild() for example).

However, this isn't true; the jQuery library actually has an internal method (which is undocumented and in theory could be changed at any time) called cleanData() (here is what this method looks like) which automatically cleans up all the data/events associated with an element upon removal from the DOM (be this via. remove(), empty(), html("") etc).


Older browsers

Older browsers - specifically older versions of IE - are known to have memory leak issues due to event listeners keeping hold of references to the elements they were attached to.

If you want a more in-depth explanation of the causes, patterns and solutions used to fix legacy IE version memory leaks, I fully recommend you read this MSDN article on Understanding and Solving Internet Explorer Leak Patterns.

A few more articles relevant to this:

Manually removing the listeners yourself would probably be a good habit to get into in this case (only if the memory is that vital to your application and you are actually targeting such browsers).

Sussman answered 21/9, 2012 at 9:43 Comment(8)
According to the jquery Documentation when using remove() method over an element, all event listeners are removed from memory. This affects the element it selft and all child nodes. If you want to keep the event listners in memory you should use .detach() instead. Useful when the removed elements are going to be inserted again on the dom.Lusk
If the element contains child elemens, will it detach event listners on child elements too?Priestly
@Lusk - that is only when using the remove method. most of the time the DOM will just get erased completely. (like turbo links or something). I am wondering how is memory affected if I do document.body.innerHTML = '' ...Regan
@Regan from my personal experience doing something like $('#EL').html('') will also remove all event of the element and child elements. So, instead of document.body.innerHtml use $('body').html('');Lusk
I would need more than "personal experience", more like hard data and tests and links to specs which say how memory keeps persistent on nodes that are no longer in the document, this is too important to just trust somebody's word without proof :)Regan
@Lusk Thanks - I've dug a bit deeper and found out how jQuery acts differently from regular JavaScript in this respect. Have updated the answer.Sussman
Does using jQuery's .empty() detach the listeners attached via addEventListener as well or just the ones attached via $(element).on()?Julie
When you say a "reference still exists" I can see how that would apply with a global variable. But what if the event listener was created inside a function? So the only reference is inside that function scope. That seems like a cycle the browser could reclaim.Triserial
E
24

regarding jQuery:

the .remove() method takes elements out of the DOM. Use .remove() when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed. To remove the elements without removing data and events, use .detach() instead.

Reference: http://api.jquery.com/remove/

jQuery v1.8.2 .remove() source code:

remove: function( selector, keepData ) {
    var elem,
        i = 0;

    for ( ; (elem = this[i]) != null; i++ ) {
        if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
            if ( !keepData && elem.nodeType === 1 ) {
                jQuery.cleanData( elem.getElementsByTagName("*") );
                jQuery.cleanData( [ elem ] );
            }

            if ( elem.parentNode ) {
                elem.parentNode.removeChild( elem );
            }
        }
    }

    return this;
}

apparently jQuery uses node.removeChild()

According to this : https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild ,

The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

ie event listeners might get removed, but node still exists in memory.

Evetteevey answered 21/9, 2012 at 10:11 Comment(2)
You're only adding confusion - jQuery does nothing that with handlers that simple removeChild wouldn't. Both also return you a reference that you may keep to reattach latter (in which case it obviously remains in memory) or throw way (in which case it is eventually picked up by GC and removed).Pareu
i know :D. so where you the one who edited the question ? cos i could have sworn that there was something about using jquery to remove a DOM element, in the question before. now my answer sounds like i'm explaining things just to stroke my ego. hey you can always downvoteEvetteevey
P
8

Don't hesitate to watch heap to see memory leaks in event handlers keeping a reference to the element with a closure and the element keeping a reference to the event handler.

Garbage collector do not like circular references.

Usual memory leak case: admit an object has a ref to an element. That element has a ref to the handler. And the handler has a ref to the object. The object has refs to a lot of other objects. This object was part of a collection you think you have thrown away by unreferencing it from your collection. => the whole object and all it refers will remain in memory till page exit. => you have to think about a complete killing method for your object class or trust a mvc framework for example.

Moreover, don't hesitate to use the Retaining tree part of Chrome dev tools.

Promise answered 7/4, 2013 at 0:3 Comment(1)
Modern garbage collectors have no problems with circular references. That was a problem when they used reference counting but they no longer do. They now determine if an object is reachable from the global object. An object that is unreachable from the global object is collected, regardless of whether that object exists in a cycle or not. This is called out specifically in developer.mozilla.org/en-US/docs/Web/JavaScript/….Pieter
A
8

Just extending other answers...

Delegated events handlers will not be removed upon element removal.

$('body').on('click', '#someEl', function (event){
  console.log(event);
});

$('#someEL').remove(); // removing the element from DOM

Now check:

$._data(document.body, 'events');
Aldora answered 8/6, 2016 at 11:58 Comment(2)
The event handler is attached to body and not #someEl, naturally the handler shouldn't be removed as long as body is still here.Paginate
This can be removed manually : #22401407Karyolymph
P
7

Regarding jQuery, the following common methods will also remove other constructs such as data and event handlers:

remove()

In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed.

empty()

To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.

html()

Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.

Pigmentation answered 30/3, 2016 at 6:39 Comment(0)
P
2

Yes, the garbage collector will remove them as well. Might not always be the case with legacy browsers though.

Plethora answered 21/9, 2012 at 9:43 Comment(1)
you statement should be supported by API documentation, examples, etc.Lubumbashi

© 2022 - 2024 — McMap. All rights reserved.