How to Garbage Collect an external Javascript load?

615 Views Asked by At

Given a loader:

function loader(src, callback, fail) {
    let s = document.head.appendChild(document.createElement('script'));
    s.type = "text/javascript";
    s.src = src;
    s.onload = function() {
        callback()
        s.onload = null; //useful?
        s = null; //or maybe this?
    }
    s.onerror = fail
}

Does having a line s.onload = null benefit from GC free some memory?

2

There are 2 best solutions below

4
Bergi On BEST ANSWER

Yes, it does benefit the GC to set the properties to null. Doing so removes the references from the element (that is contained in the DOM) to the handler function, and given that it probably is the only reference to the function it makes the function eligible for collection. However, unless the function is a closure over variables retaining a large block of memory, this is very unlikely to have a lot of impact.

You might also want to remove the s element from the DOM in the callback, making it garbage-collectable as well.

3
AudioBubble On

Yes, s.onload = null is useful and will garbage collect!

As of 2019, it is not possible to explicitly or programmatically trigger garbage collection in JavaScript. That means it collects when it wants.
Although there is cases where setting to null may do a GC earlier (but not trigg it to do).

As of 2012, all modern browsers ship a mark-and-sweep garbage-collector.
It works from a principle of reachibility:

Every object not reachable from the global context is deleted

Periodically the mark-and-sweep discover and deletes an object when every variable that holded it is returned, reassigned or set to null. Also it is nowadays not needed to recursively set null on content that is not reachable from any variable - it is collected anyway by the mark-and-sweep.

Now to the code in question ...

The s = null is not needed, because the variable cleares anyway when function returns, closure is removed from the call-stack and GC takes care of s.

but there still is a reference to the scripts onload property, as the <script onload> is a child of the document.head in the DOM reachable from the window!

Content of the callback may be reachable, but is out of question here.

What if browsers is smart enough to set s.onload = null internally? We try it out by first comment it away in the first snippet and uncomment it in the second snippet ...

function fetch(src, callback, fail) {
    let s = document.head.appendChild(document.createElement('script'));
    s.type = "text/javascript";
    s.src = src;
    s.onload = function() {
        callback()
        //s.onload = null; //useful?
    }
    s.onerror = fail
}

fetch("https://stackoverflow.com", 
       () => {console.log("Execute onload");}, 
       () => {console.log("File not found");})

setTimeout(() => {
    console.log(document.head.lastChild.onload)
},1000)

The found file is executed with error, because it is not Javascript.
The onload is executed but not removed. The code show up in the log!
That proves the line with s.onload = null should be used, like this:

function fetch(src, callback, fail) {
    let s = document.head.appendChild(document.createElement('script'));
    s.type = "text/javascript";
    s.src = src;
    s.onload = function() {
        callback()
        s.onload = null; //useful!
    }
    s.onerror = fail
}

fetch("https://stackoverflow.com", 
       () => {console.log("Execute onload");}, 
       () => {console.log("File not found");})

setTimeout(() => {
    console.log(document.head.lastChild.onload)
},1000)