JavaScript DOM操作内存泄漏

3

你好,我已经使用原生JavaScript DOM创建了一个DOM:

Javascript代码:

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);

生成的HTML代码如下:
<div id="parent">
    <p id="child1">Hello</p>
    <p id="child2">World</p>
</div>

现在,当我想要删除上述部分时,我按照以下步骤进行操作。
document.body.removeChild(parentElm);

在这里,我担心Javascript内存泄漏问题。

  • 如果我从body中删除父元素,它会完全从内存中删除吗?
  • 如果我从body中删除父元素,它的子元素是否会被垃圾回收器自动从内存中删除?还是我需要手动删除子元素?
  • 在上面的代码中使用innerHTML是否是一个好方法(child1.innerHTML = "Hello";)?

请帮我处理Javascript DOM操作。

1个回答

7
如果我从body中删除父元素,它会完全从内存中删除吗?
如果你的parentElm、child1和child2变量不再在作用域内或者你已经将它们设置为其他值,那么是的。
如果我从body中删除父元素,它的子元素是否会被垃圾收集器自动清除?还是我需要手动删除子元素?
如果你的child1和child2变量不再在作用域内或者你已经将它们设置为其他值,那么是的,删除父元素就足以删除子元素并允许它们被清理。
在上面的代码中使用innerHTML是一个好的方法吗(child1.innerHTML =“Hello”;)?
这是可以的,也是常见的做法。
所以这里没有内存泄漏,例如:
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"));

因为addParagraphs中的变量都可以被回收,所以这种做法是可行的。

但是,如果你在这些变量上创建了一个闭包并保持它,那么它会使元素在内存中的存储时间比你预期的要长:

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"));

我们从addParagraphs返回并存储在f中的函数是对其创建上下文的一个闭包。理论上,即使函数不使用parentElmchild1child2,它仍然有一个对其创建位置的上下文的引用,而该上下文则引用了这些变量,使其保留在内存中。(现代JavaScript引擎可以对此进行优化。)因此,只要我们有对f的引用,那些DOM元素就仍然存在于内存中,并由保持活动的变量所保持活动。如果你释放f,它就不一定是一个泄漏,但记住这点还是很有用的。


当然,你也可以用更少的代码来创建这些元素:

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

或者在现代浏览器上:

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

非常感谢。我明白了你的意思。只是为了澄清,当删除任何节点时,我需要将其引用分配给其他值,例如null吗?同时需要对其子元素执行相同的操作吗? - Dinesh Patra
谢谢您先生。这非常有帮助。我总是因为对内部HTML的了解不足而感到害怕,担心会出现内存泄漏。现在明白了。您能否提供一些关于DOM操作的参考资料,避免出现内存泄漏? - Dinesh Patra
@DineshPatra: "当删除任何节点时,我需要将其引用分配给其他值,例如null?" 你不是在分配给"它的引用",而是在分配给一个变量(或属性)。只有当某些东西将保留该变量(或属性)在内存中时,才需要这样做。但是,如果您已经完成使用该元素,则将null分配给变量/属性最多是无害的,有时还很有用。关于innerHTML:我从未听说过与innerHTML相关的内存泄漏问题。恐怕我不知道这个主题的好参考资料。 - T.J. Crowder
非常感谢您,先生。 - Dinesh Patra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接