Javascript 如何在没有内存泄漏的情况下删除 DOM 元素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3785258/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:09:09  来源:igfitidea点击:

How to remove DOM elements without memory leaks?

javascriptjquerydommemory-leaks

提问by podeig

My JavaSript code builds a list of LIelements. When I update the list, memory usage grows and never goes down. I tested in sIEve and it shows that the browser keeps all elements that were supposed to be deleted by $.remove()or $.emptyjQuery commands.

我的 JavaSript 代码构建了一个LI元素列表。当我更新列表时,内存使用量会增加并且永远不会减少。我在 sIEve 中进行了测试,它显示浏览器保留了应该由$.remove()$.emptyjQuery 命令删除的所有元素。

What should I do to remove DOM nodes without the memory leak?

我应该怎么做才能在没有内存泄漏的情况下删除 DOM 节点?

See my other questionfor the specific code.

具体代码见我的其他问题

回答by Randy the Dev

The DOM preserves all DOM nodes, even if they have been removed from the DOM tree itself, the only way to remove these nodes is to do a page refresh (if you put the list into an iframe the refresh won't be as noticable)

DOM 保留所有 DOM 节点,即使它们已从 DOM 树本身中删除,删除这些节点的唯一方法是进行页面刷新(如果您将列表放入 iframe,刷新将不会那么明显)

Otherwise, you could wait for the problem to get bad enough that the browsers garbage collector is forced into action (talking hundreds of megabytes of unused nodes here)

否则,您可以等待问题变得足够严重,以至于浏览器垃圾收集器被迫采取行动(此处讨论数百兆字节的未使用节点)

Best practice is to reuse nodes.

最佳实践是重用节点。

EDIT: Try this:

编辑:试试这个:

var garbageBin;
window.onload = function ()
    {
    if (typeof(garbageBin) === 'undefined')
        {
        //Here we are creating a 'garbage bin' object to temporarily 
        //store elements that are to be discarded
        garbageBin = document.createElement('div');
        garbageBin.style.display = 'none'; //Make sure it is not displayed
        document.body.appendChild(garbageBin);
        }
    function discardElement(element)
        {
        //The way this works is due to the phenomenon whereby child nodes
        //of an object with it's innerHTML emptied are removed from memory

        //Move the element to the garbage bin element
        garbageBin.appendChild(element);
        //Empty the garbage bin
        garbageBin.innerHTML = "";
        }
    }

To use it in your context, you would do it like this:

要在您的上下文中使用它,您可以这样做:

discardElement(this);

回答by FK82

This is more of an FYIthan an actual answer, but it is also quite interesting.

这与其说是一个实际答案,不如说是一个仅供参考,但它也很有趣。

From the W3C DOM core specification(http://www.w3.org/TR/DOM-Level-2-Core/core.html):

来自 W3C DOM 核心规范(http://www.w3.org/TR/DOM-Level-2-Core/core.html):

The Core DOM APIs are designed to be compatible with a wide range of languages, including both general-user scripting languages and the more challenging languages used mostly by professional programmers. Thus, the DOM APIs need to operate across a variety of memory management philosophies, from language bindings that do not expose memory management to the user at all, through those (notably Java) that provide explicit constructors but provide an automatic garbage collection mechanism to automatically reclaim unused memory, to those (especially C/C++) that generally require the programmer to explicitly allocate object memory, track where it is used, and explicitly free it for re-use. To ensure a consistent API across these platforms, the DOM does not address memory management issues at all, but instead leaves these for the implementation. Neither of the explicit language bindings defined by the DOM API (for ECMAScript and Java) require any memory management methods, but DOM bindings for other languages (especially C or C++) may require such support. These extensions will be the responsibility of those adapting the DOM API to a specific language, not the DOM Working Group.

Core DOM API 旨在与多种语言兼容,包括通用用户脚本语言和专业程序员主要使用的更具挑战性的语言。因此,DOM API 需要在各种内存管理哲学中运行,从根本不向用户公开内存管理的语言绑定,到那些提供显式构造函数但提供自动垃圾收集机制以自动回收未使用的内存,用于那些(尤其是 C/C++)通常需要程序员显式分配对象内存、跟踪它的使用位置并显式释放它以供重用的内存。为了确保跨这些平台的 API 一致,DOM 根本不解决内存管理问题,而是将这些问题留给实现。DOM API 定义的显式语言绑定(用于 ECMAScript 和 Java)都不需要任何内存管理方法,但其他语言(尤其是 C 或 C++)的 DOM 绑定可能需要这种支持。这些扩展将由那些使 DOM API 适应特定语言的人负责,而不是 DOM 工作组。

In other words: memory management is left to the implementation of the DOM specification in various languages. You would have to look into the documentation of the DOM implementation in javascript to find out any method to remove a DOM object from memory, which is not a hack. (There is however very little information on the MDC site on that topic.)

换句话说:内存管理留给了 DOM 规范在各种语言中的实现。您必须查看 javascript 中 DOM 实现的文档,以找出从内存中删除 DOM 对象的任何方法,这不是黑客攻击。(然而,关于该主题的 MDC 站点上的信息很少。)



As a note on jQuery#removeand jQuery#empty: from what I can tell neither of these methods does anything other than removing Objects from DOM nodes or removing DOM nodes from the document. They only remove That of course does not mean that there is no memory allocated to these objects (even though they aren't in the documentanymore).

作为一个说明上jQuery#removejQuery#empty:从我可以告诉这些方法都不做不是删除其他任何Object从DOM小号nodeS或移除DOMnode从S document。他们只删除 那当然并不意味着没有分配给这些对象的内存(即使它们document不再存在)。

Edit:The above passage was superfluous since obviously jQuery cannot do wonders and work around the DOM implementation of the used browser.

编辑:上面的段落是多余的,因为显然 jQuery 不能创造奇迹并解决所用浏览器的 DOM 实现。

回答by Skilldrick

Have you removed any event listeners? That can cause memory leaks.

您是否删除了任何事件侦听器?这会导致内存泄漏

回答by Mic

The code below does not leak on my IE7 and other browsers:

下面的代码不会在我的 IE7 和其他浏览器上泄漏:

<html>
<head></head>
<body>
    <a href="javascript:" onclick="addRemove(this)">add</a>
    <ul></ul>
    <script>
        function addRemove(a) {
            var ul = document.getElementsByTagName('UL')[0],
                li, i = 20000;
            if (a.innerHTML === 'add') {
                while (i--) {
                    li = document.createElement('LI');
                    ul.appendChild(li);
                    li.innerHTML = i;
                    li.onclick = function() {
                        alert(this.innerHTML);
                    };
                }
                a.innerHTML = 'remove';
            } else {
                while (ul.firstChild) {
                    ul.removeChild(ul.firstChild);
                }
                a.innerHTML = 'add';
            }
        }
    </script>
    </body>
</html>

May be you can try to spot some differences with your code.
I know that IE leaks far less when you insert first the node in the DOM before doing anything to it, eg: attaching events to it or filling its innerHTMLproperty.

也许您可以尝试发现您的代码的一些差异。
我知道在对 DOM 执行任何操作之前先将节点插入 DOM 时,IE 泄漏要少得多,例如:将事件附加到它或填充其innerHTML属性。

回答by Jens

If you have to "post-fix" leakage, and must do so without rewriting all your code to take closures, circular references etc in account, use Douglas Crockfords Purge-method prior to delete:

如果您必须“后修复”泄漏,并且必须在不重写所有代码以考虑闭包、循环引用等的情况下这样做,请在删除之前使用 Douglas Crockfords Purge-method:

https://crockford.com/javascript/memory/leak.html

https://crockford.com/javascript/memory/leak.html

Or use this closure-fix workaround:

或使用此关闭修复解决方法:

Leak Free Javascript Closures

无泄漏 Javascript 关闭