Javascript: document.createElement('') & delete DOMElement - javascript

If you create a element within a function like:
function makeDomElement()
{
var createdElement = document.createElement('textarea');
}
And you do not append it anywhere in the DOM i.e. via .appendChild functions, does it still remain in memory? So would you have to do
function makeDomElement()
{
var createdElement = document.createElement('textarea');
delete createdElement;
}
I'm just curious :)

It will vary from browser to browser however the javascript delete keyword has nothing to do with the DOM's createElement method. There is no need to use delete.
What will happen is that the reference to the element currently held in the createdElement will get garbage collected. Now in the case of IE that will mean that the element will have its reference count dropped to 0 so it will destroy itself and release its memory. Other browsers do things differently typically the elements in the DOM are themselves garbage collected objects and will be removed during the same (or perhaps a DOM specific) GC cycle.
Had the element been added to the document then in the case of IE there would be another reference added to the element so when the reference in createdElement is removed the element object would still have a non-zero reference count and continue to exist.
In the case of other browsers where the elements themselves are garbage collected the element wouldn't be collected since the collector would see it in the graph of objects connected to the document.

After the function terminates, there's no longer any reference to the object, ie if the garbage collector works properly, it should be collected (there's an IE bug that prevents objects with circular references to be collected if DOM nodes are involved).
Also, your code is broken as local variables can't be deleted: trying to do so will even throw a syntax error in strict mode ES5.

Related

will removing an HTML element going to cause his and his childrens EventListeners to get deleted? [duplicate]

If a DOM Element is removed, are its listeners removed from memory too?
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:
JScript memory leaks
Memory leaks in IE8
JavaScript Memory Leaks
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).
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.
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.
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');
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.
Yes, the garbage collector will remove them as well. Might not always be the case with legacy browsers though.

Remove DOM element explicitly to avoid memory leakage in javascript

I was checking the doc in MDN about garbage collection. When I come across the 'Real-life example' section, the term 'explicitly removed' in below statement confused me.
If the property is not explicitly removed or nulled, a reference-counting garbage collector will always have at least one reference intact and will keep the DOM element in memory even if it was removed from the DOM tree
Can document.removeChild fulfill the criteria of removing DOM element explicitly?
Can document.removeChild fulfill the criteria of removing DOM element explicitly?
The question indicates some confusion: there is no criteria to explicitly remove the DOM node. Removing an element from the DOM, either explicitly or implicitly (by removing an ancestral element from it descends), should make it available for memory collection assuming no reference to the removed element is retained in code. The property mentioned at the beginning of the quoted article refers to the div.circularReference property used in the example, whose value was set to div to create a circular reference back from the property to the element.
Explicitly removing "the property" could be achieved by deleting or changing the property's value, for example with
div.circularReference = null; // or
delete div.circularReference;
Removing the circular reference could be done before or after removal of div from the DOM. The good news is where the article says reference-counting garbage collector are no longer used in modern browsers.

DOM node.remove() does not invalidate Javascript Variable Reference. How to fix that?

I did this simple test in Chromium Console:
var e = document.querySelector('#myElement');
e.remove();
//But here, 'e' still references the original node even though its no longer in the DOM.
I don't want this behavior. I would like 'e' to act more like a Weak Reference, whereby it would change to NULL or UNDEFINED or something indicating the node has been destroyed.
I understand that the problem is due to the fact that the node technically still exists even though its not part of the DOM anymore. I speculate it will hang around until the browser deems an appropriate time to garbage collect it.
So instead of simply doing .remove(), is there a way to really destroy/delete the node so that all variables referencing it will become undefined or null or some effect that can be detected later?
Thanks in advance!
Also, I speculate this behavior will vary highly between browsers. So any feedback that mentions Non-Chromium browsers is highly welcome also. :)
If a standalone variable holds a reference to an object, and that variable can still be referenced, the object will not get picked up by the garbage collector's mark-and-sweep algorithm, and the object will continue to exist at least as long as the variable can still be referenced.
Given a reference to an object, you cannot destroy it such that other references to the object break.
JavaScript doesn't provide the sort of manual memory control you're looking for, unfortunately.
You can put the element into a WeakSet, after which removing the element from the DOM will eventually cause the element being removed from the WeakSet if nothing else can possibly reference the element - but that's not really what you're looking for.
There do exist WeakRefs, an extremely new API, which allow variables to be specially declared such that what they reference can be garbage collected despite them still being referenceable:
const ref = (() => {
const e = document.querySelector('#myElement');
const ref = new WeakRef(e);
e.remove();
return ref;
})();
With the above, calling ref.deref() will eventually give you undefined if nothing else can reference the element and it has been garbage collected. (Until it gets garbage collected, .deref() will give you the element.)

Right way to free memory in JavaScript

Being a C developer, I feel the urgent need to free memory as accurately as possible. But after reading some posts about memory management in JavaScript I still have some questions about that topic. As far as I understand, there is a garbage collector that will automatically free the memory when an object isn't referenced anymore and the GC can find the time. So an object that is held in a local variable is very likely to be freed when the variable goes out of scope.
Let's assume I have some custom elements (tab control, data table, inputs etc.). The classes of those custom elements have member variables where several data for the specific element is stored. Also event listeners can be attached to the elements the custom element consists of.
Let's say I have following html markup:
<my-tabbar>
<my-tab id="myTab">
<my-input></input>
<my-dataTable></my-dataTable>
</my-tab>
</my-tabbar>
Now I want to remove <my-tab>. Is it sufficient to just do
var element = document.getElementById ("myTab");
element.parentNode.removeChild (element);
element = null;
Or do I have to dereference every object of the child elements and remove their event listeners?
Setting an object to null makes it an empty object. Once the object is out of scope, the GC (when it runs) will clear it up. Setting local objects to null won't do you any good.
Example:
function whatever()
{
var something = null;
console.log( typeof( something ) );
}
whatever();
Output:
"object"
For the removal of a child node, please see this:
Does removeChild really delete the element?
Source(s):
https://www.w3schools.com/js/js_datatypes.asp
It is sufficient to remove the element. You don't even have to set the variable to null afterwards – you can trust the JS engine to free the memory when it goes out of scope.

Does removeChild really delete the element?

Does removeChild function really delete the child node completely? Or it just removes the element being child of the specified parant node? If it doesn't really deletes the element, is there a way to delete the element completely?
The removeChild method simply removes it from its parent. If it’s a visible element of the page, it will be removed from the page.
But Javascript has garbage collection. This means that the node object itself will remain in existence as long as any variable refers to it. So you can assign a node to a variable, use removeChild to 'prune' it from its parent node, and later on, insert or append it to some other node, thereby effectively moving it around on the page.
The following code will remove a node, and wait 10 seconds before re-adding it to the tree (and thus, to the page):
var oldNode = someNode.removeChild(...);
setTimeout(function () {
document.documentElement.appendChild(oldNode);
}, 10000);
This means that the node object hasn’t been deleted from memory, because there’s still a variable pointing to it (namely, oldNode).
Another case:
var node = document.getElementById('test');
// ... do stuff
node.parentElement.removeChild(node);
// 'node' still exists, but has been removed from the page
// ... do some more stuff
node = document.getElementById('hello');
// The variable 'node' now points to something else;
// this means the original node will be deleted from memory
If, on the other hand, you don’t reassign the removed node to another variable, it can’t be accessed anymore (not via the document tree, since it’s been removed from there; and not via a JS variable); so Javascript will automatically purge it from memory:
someNode.removeChild(...);
Assigning the removed node to a variable, and then assigning null (or anything else) to that variable — like Marc B suggests in his answer — is completely unnecessary and, IMHO, silly.
This will completely delete the node:
someNode.removeChild(...);
This will remove the node from the DOM so it's not visible but will save it so that you can insert it elsewhere:
oldNode = someNode.removeChild(...);
removeChild removes the element from the dom, but it's also returned from the function in case you're doing the removal to re-insert it elsewhere. You'd have to kill that return value to really get rid of the removed node:
oldNode = someNode.removeChild(...);
oldNode = null;
If you want to really delete a dom element . removeChild alone is not enough. This is as per Steve Sounders who is the author of YSlow. You need to use delete

Categories

Resources