Resolving memory issues with HTML replacement and Ajax
In Illyriad we do very large numbers of ajax requests using jQuery over a players session. Some of these are pure data requests, but many of them are navigational HTML page replacements.
A simple replacement seems to leak memory in various browsers:
[code lang=”js”]
$(‘#ElementToReplaceContents’).html(htmlToReplaceWith);
[/code]
Even calling the jQuery function .empty() before the replacement doesn’t seem to help in all cases. To fix this we have created a clean up function which is a common or garden “overkill” variety which seems to do the trick. Usage below:
[code lang=”js”]
function ChangeLocationSucess(data, textStatus, XHR) {
if (XHR.status == 200) {
var div = $(‘#ElementToReplaceContents’);
DoUnload(); // More on this further down
div.RemoveChildrenFromDom(); // Clean up call
div.html(data); // HTML replacement
}
…
[/code]
Clearing the memory from the existing HTML is done with the clean up code below:
[code lang=”js” title=”Added: RemoveChildrenFromDom jQuery plugin”]
(function( $ ){
$.fn.RemoveChildrenFromDom = function (i) {
if (!this) return;
this.find(‘input[type="submit"]’).unbind(); // Unwire submit buttons
this.children()
.empty() // jQuery empty of children
.each(function (index, domEle) {
try { domEle.innerHTML = ""; } catch (e) {} // HTML child element clear
});
this.empty(); // jQuery Empty
try { this.get().innerHTML = ""; } catch (e) {} // HTML element clear
};
})( jQuery );
[/code]
Some pages have extra resources cached and extra elements with wired up events. For these we have introduced a DoUnload function which also gets called before the replacement. This runs through the list of on page clean up functions and calls them one by one:
[code lang=”js” title=”Extra clean up system”]
var unloadFuncs = [];
function DoUnload() {
while (unloadFuncs.length > 0) {
var f = unloadFuncs.pop();
f();
f = null;
}
}
[/code]
We create these unload functions on the page that has any extra clean up to do by using the following code; which adds clean up functions to the unloadFuncs array above. This code looks like the code below:
[code lang=”js” title=”On page clean up registration”]
var unload = function() {
OnPageCachedResources.clear(); // Clear array of cached resources
OnPageCachedResources = null;
$("#OnPageElementWithWiredUpEvents")
.unbind()
.undelegate(); // Remove attached events
}
unloadFuncs.push(unload);
[/code]
Obviously this varies from page to page and most of our pages don’t need it – at which point the DoUnload function just returns with out doing work.
This coupled with the Fix for IE and JQuery 1.4 Ajax deal with most of the regular unexpected leaks.
(As an aside: When replacing HTML with Ajax, do not wire up events using onclick=”” etc in the HTML or this will also leak. Use event binding from script – a third party library like jQuery, Prototype or Dojo will make this very straight forward)