What is the purpose of $.cache in jQuery?

2019-03-15 02:28发布

I see that the event handlers registered through .on() are held in $.cache. I also see that the event handlers are also held in $(elem).data().

The objects held in $.cache refer to the DOM nodes on which the events are registered. This leads to memory leak when the DOM nodes are detached, and this makes .off() calls mandatory.

I have a situation where I don't know when the DOM node (to which I attached the event handler) is being detached. While I can hold the reference to that DOM node in my code and call .off() to clean up, it doesn't seem nice, because it is not straightforward to know when the DOM node is being removed.

What is the best way to do this?

2条回答
叼着烟拽天下
2楼-- · 2019-03-15 02:46

I ran in to a similar situation where Knockout is used to add and remove dom trees from the document. However, jquery is used to attach event listeners to these dom trees. When knockout removes dom elements from the document the listeners are not unbound so the dom tree is never eligible for garbage collection. We have added a clean up function that trawls through the jquery $.cache everytime the hash changes and finds even handlers that are bound to dom trees that are not in the document. It then unbinds the listeners thus making the dom tree eligible for garbage collection and fixing most of the leaks that we are seeing i.e. round trip round the app used to leak 13MB now it leaks just 3MB with these changes in place.

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;
                }
            }
        }
查看更多
Explosion°爆炸
3楼-- · 2019-03-15 03:08

"What is the best way to do this?"

If you're going to use jQuery, you must use its API for removing elements, and you must use the proper methods, otherwise, as you stated, you'll have memory leaks.

If you don't know when the DOM node is being removed, and if it is causing a leak, I'd assume this means that you are using another library alongside jQuery. That's just not a good idea for this very reason.

You need to ensure that any elements affected by jQuery are removed by jQuery. There's also some data stored in $.cache that you didn't explicitly set. This means that all elements should be removed with jQuery, instead of just those that you think may have data.


"What is the purpose of $.cache in jQuery?"

To associate handlers and other data with elements. The link between the data and the elements is basically a serial number stored on an expando property on the element.

If you remove the element without jQuery, the associated data in $.cache is orphaned.

The purpose of this approach was to prevent potential leaks. Unfortunately it potentially creates more severe leaks.

查看更多
登录 后发表回答