Javascript dom manipulation memory leak

2019-05-23 08:43发布

问题:

Hi I have created a dom using raw javascript DOM:

Javascript code:

var parentElm = document.createElement("div");
var child1 = document.createElement("p");
var child2 = document.createElement("p");

parentElm.id = "parent";
child1.id = "child1";
child2.id = "child2";

child1.innerHTML = "Hello";
child2.innerHTML = "world"; // Is it a good way 

parentElm.appendChild(child1);
parentElm.appendChild(child2);
document.body.appendChild(parentElm);

The resulted HTML is:

<div id="parent">
    <p id="child1">Hello</p>
    <p id="child2">World</p>
</div>

Now when I want to remove the above section, I do as following.

document.body.removeChild(parentElm);

Here I am afraid of javascript memory leak.

  • If I am removing parent element from body, does it totally removed from memory. ?
  • If I am removing parent element from body, does it's child elements are also removed from memory by garbage collector automatically. Or I need to remove child elements manually ?
  • Is using innerHTML in the above code is a good way (child1.innerHTML = "Hello";)

Please help me in javascript dom manipulation.

回答1:

If I am removing parent element from body, does it totally removed from memory. ?

If your parentElm, child1, and child2 variables are no longer in scope or you've set them to another value, yes.

If I am removing parent element from body, does it's child elements are also removed from memory by garbage collector automatically. Or I need to remove child elements manually ?

If your child1 and child2 variables are no longer in scope or you've set them to another value, yes, removing the parent is all you need to do to remove the children and allow them to be cleanned up.

Is using innerHTML in the above code is a good way (child1.innerHTML = "Hello";)

It's fine, and common practice.

So there's no memory leak here, for instance:

function addParagraphs() {
    var parentElm = document.createElement("div");
    var child1 = document.createElement("p");
    var child2 = document.createElement("p");

    parentElm.id = "parent";
    child1.id = "child1";
    child2.id = "child2";

    child1.innerHTML = "Hello";
    child2.innerHTML = "world"; // Is it a good way 

    parentElm.appendChild(child1);
    parentElm.appendChild(child2);
    document.body.appendChild(parentElm);
}

function removeElement(element) {
    if (element.remove) {
        element.remove(); // newer DOM method, not on all browsers
    } else if (element.parentNode) {
        element.parentNode.removeChild(element);
    }
}

addParagraphs();
removeElement(document.getElementById("parent"));

...because the variables in addParagraphs can all be reclaimed.

However, if you create a closure over those variables and you keep it, that can keep the elements in memory longer than you expect:

function addParagraphs() {
    var parentElm = document.createElement("div");
    var child1 = document.createElement("p");
    var child2 = document.createElement("p");

    parentElm.id = "parent";
    child1.id = "child1";
    child2.id = "child2";

    child1.innerHTML = "Hello";
    child2.innerHTML = "world"; // Is it a good way 

    parentElm.appendChild(child1);
    parentElm.appendChild(child2);
    document.body.appendChild(parentElm);

    return function() {
        console.log("Hi there");
    };
}

function removeElement(element) {
    if (element.remove) {
        element.remove(); // newer DOM method, not on all browsers
    } else if (element.parentNode) {
        element.parentNode.removeChild(element);
    }
}

var f = addParagraphs();
removeElement(document.getElementById("parent"));

The function we return from addParagraphs and store in f is a closure over the context it was created in. In theory, even though the function doesn't use parentElm, child1, or child2, it has a reference to the context where it was created, and that context has a reference to those variables, keeping them in memory. (Modern JavaScript engines can optimize this a bit.) So in theory, as long as we have a reference to f, those DOM elements can still exist in memory, kept alive by the variables that are kept alive by the function. It's still not necessarily a leak, if you release f at some point, but it's useful to remember.


Of course, you can also create those elements with less code:

var parentElm = document.createElement('p');
parentElm.id = "parent";
parentElm.innerHTML =
    '<p id="child1">Hello</p>' +
    '<p id="child2">world</p>';
document.body.appendChild(parentElm);

Or on modern browsers:

document.body.insertAdjacentHTML(
    'beforeend',
    '<p id="parent">' +
        '<p id="child1">Hello</p>' +
        '<p id="child2">world</p>' +
    '</p>'
);