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?
The cache: false is used by developers to prevent all future AJAX requests from being cached, regardless of which jQuery method they use. We can use $. ajaxSetup({cache:false}); to apply the technique for all AJAX functions.
cache:true is the default and does not always get the content from the cache. The cache-ability of an item on the browser is determined by: The response headers returned from the origin web server. If the headers indicate that content should not be cached then it won't be.
Although we can use a standard caching solution provided by HTTP (yes, Ajax is cached by HTTP), there is a catch: It works for GET requests only (not POST).
In computing, a cache is a high-speed data storage layer which stores a subset of data, typically transient in nature, so that future requests for that data are served up faster than is possible by accessing the data's primary storage location.
"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.
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;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With