【问题标题】:What is the purpose of $.cache in jQuery?jQuery 中 $.cache 的目的是什么?
【发布时间】:2012-02-16 02:40:29
【问题描述】:

我看到通过.on() 注册的事件处理程序保存在$.cache 中。 我还看到事件处理程序也保存在$(elem).data()

$.cache 中保存的对象指的是注册事件的 DOM 节点。当 DOM 节点被分离时,这会导致内存泄漏,这使得 .off() 调用是强制性的。

我有一种情况,我不知道 DOM 节点(我附加了事件处理程序)何时被分离。虽然我可以在我的代码中保存对该 DOM 节点的引用并调用 .off() 进行清理,但这似乎并不好,因为要知道何时删除 DOM 节点并不容易。

最好的方法是什么?

【问题讨论】:

    标签: jquery dom memory-leaks


    【解决方案1】:

    “最好的方法是什么?”

    如果你打算使用 jQuery,你必须使用它的 API 来删除元素,并且你必须使用正确的方法,否则,正如你所说,你会出现内存泄漏。

    如果您不知道 DOM 节点何时被删除,并且如果它导致泄漏,我会假设这意味着您正在使用 jQuery 旁边的另一个库。由于这个原因,这不是一个好主意。

    您需要确保任何受 jQuery 影响的元素都被 jQuery 删除。 $.cache 中还存储了一些您没有明确设置的数据。这意味着应该使用 jQuery 删除 所有 元素,而不仅仅是那些您认为 可能有数据的元素。


    “jQuery 中$.cache 的作用是什么?”

    将处理程序和其他数据与元素相关联。数据和元素之间的链接基本上是存储在元素上的 expando 属性上的序列号。

    如果不使用 jQuery 删除元素,$.cache 中的关联数据将被孤立。

    这种方法的目的是防止潜在的泄漏。不幸的是,它可能会造成更严重的泄漏。

    【讨论】:

    • 1.如果元素和处理程序之间的关系是通过序列号维护的(并且如果处理程序没有引用元素),我看不出 .cache 条目应该导致内存泄漏的原因。出于某种原因,我不知道这是多么合理,缓存条目是指该元素。我很想知道为什么需要对元素的引用。 2. 我不知道元素的 expando 不能直接保存对对象(处理程序)的引用的情况。如果 expando 可以保存引用,我认为不需要像 .cache 这样的并行结构来保存引用。
    • @user968903: 1. 如果您在删除元素时不使用 jQuery 的方法删除相关的 $.cache 条目,它们只会导致泄漏。序列号是两者之间的唯一联系,因此如果序列号为123 的元素被删除,但jQuery 没有删除$.cache 中的条目123,那么该条目现在指的是不再具有相应的元素,并且永远不会被清理。理由是主要存在于 IE6 和 IE7 中的潜在内存泄漏。现在那些浏览器都快没了,不知道这种做法好不好。
    • @user968903: 2. 我认为现代浏览器在删除元素时通常会清理元素,所以它可能不再是什么大问题了。我相信主要是 IE6/7 有问题。我认为关于闭包可能仍然存在潜在的内存泄漏,其中一个元素有一个处理程序,该处理程序在其变量范围内具有对自身的循环引用,但我不确定这是否是今天的问题。我会看看我能找到什么。
    【解决方案2】:

    我遇到了类似的情况,使用 Knockout 从文档中添加和删除 dom 树。但是,jquery 用于将事件侦听器附加到这些 dom 树。当敲除从文档中删除 dom 元素时,侦听器并未解除绑定,因此 dom 树永远不符合垃圾收集的条件。我们添加了一个清理函数,该函数在每次哈希更改时遍历 jquery $.cache 并找到绑定到文档中未包含的 dom 树的处理程序。然后它解除绑定侦听器,从而使 dom 树有资格进行垃圾收集并修复我们看到的大部分泄漏,即应用程序的往返泄漏 13MB 现在它只泄漏了 3MB 并进行了这些更改。

    for (var i in $.cache) {
                if ($.cache.hasOwnProperty(i)) {
    
                    if ($.cache[i].handle && $.cache[i].handle.elem && document !== $.cache[i].handle.elem && !jQuery.contains(document, $.cache[i].handle.elem)) {
                        //we have an event handler pointing to a detached dom element!
                        //this is a memory leak as this detached dom element cannot be garbage collected until
                        //all references to it are removed. So lets delete the event handler to get memory back!
                        var orphan = $($.cache[i].handle.elem);
                        $('body').append(orphan);
                        orphan.off();
                        orphan.remove();
                        orphan = null;
                    }
                }
            }
    

    【讨论】:

    • 看起来这是淘汰 3.0.0 中的一个错误的结果,当我升级到 3.1.0 时,内存泄漏消失了,不需要上面的代码!
    猜你喜欢
    • 2020-01-18
    • 2020-11-29
    • 2015-11-25
    • 2021-01-26
    • 2011-11-24
    • 2012-11-03
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    相关资源
    最近更新 更多