I’ve been searching the web for a while now, and I haven’t come across a conclusive solution for memory leaks due to replacing nodes with frequent AJAX updates.
I wrote a class that pulls an RSS feed frequently (e.g. every 5 seconds) and updates an HTML element with new information. In the process, it removes the old nodes and replaces them with new ones. It works fine visually. The only problem is that it has terrible memory leak complications; when I put the script on to run, it increases the memory usage by about 1MB every few seconds at an accelerated 1000-ms delay between updates! (That’s 100MB every few minutes!) I discovered this when I let the script run for a few hours straight, not thinking anything of it, and when I returned to my computer, it was frozen up Opera seems to be the worst at its memory management on this script, Safari and Chrome are in the middle, and Firefox seems to handle it the best, but nonetheless there are memory leaks in all four. (I haven’t tested IE yet, but based on what I read, I would expect that it might even be worse than Opera!)
Here is my code:
var AJAXData = new Array();
function AJAXml(ajaxurl, ajaxcallback){
var ajaxid;
do{
ajaxid = Math.random().toString();
}while(AJAXData[ajaxid]);
AJAXData[ajaxid] = getXMLReqObj();
AJAXData[ajaxid].callback = ajaxcallback;
AJAXData[ajaxid].onreadystatechange = function(){
if(this.readyState==4 && this.status==200){
this.callback(this.responseXML);
}else if(this.readyState==4){
window.status = "Error: "+this.statusText;
}
}
AJAXData[ajaxid].open("GET", ajaxurl, true);
AJAXData[ajaxid].send(null);
return ajaxid;
}
function createFunctionReference(cfrobject, cfrmethod){
var cfrfunc = function(){
cfrmethod.apply(cfrobject, arguments);
}
return cfrfunc;
}
function RSSFeed(rssfref, rssfurl, rssftarget, rssfreloaddelay){
this.url = rssfurl;
this.target = rssftarget;
this.delay = rssfreloaddelay;
this.ref = rssfref;
var rssLoadingInProgress = false;
this.initRSS = function(irevt){
this.target = document.getElementById(this.target);
this.loadRSS();
}
this.loadRSS = function(lrevt){
if(rssLoadingInProgress) return;
rssLoadingInProgress = true;
AJAXml(this.url, createFunctionReference(this, this.processRSS));
}
this.processRSS = function(prxml){
rssLoadingInProgress = false;
var pritems = prxml.getElementsByTagName("item");
var prarr = new Array();
for(var pri in pritems){
if(!pritems[pri].nodeType) continue;
/* pritems[pri].time is actually parsed and
processed, but for sake of clarity, I'll post
a generic substitution instead. If it's
important to see this function, let me know,
and I can post the whole thing. */
pritems[pri].time = {format:"Time formatted", collate=Math.random()};
if(prarr.length==0){
prarr.push(pritems[pri]);
}else{
var prscan = 0;
while(prscan<prarr.length){
if(prarr[prscan].time.collate < pritems[pri].time.collate){
prarr.splice(prscan, 0, pritems[pri]);
break;
}
prscan++;
}
if(prscan==prarr.length) prarr.push(pritems[pri]);
}
}
/* This method goes through and "nullifies" the
nodeValue of all child nodes (and children of
children, and attributes) before removing them */
this.target.clearChildNodes();
var printnum = 0;
for(var printnum=0; printnum<10; printnum++){
var pritem = prarr[printnum];
// A lot of document.createElement() stuff here, formatting the RSS for the user
this.target.appendChild(pr_div);
}
prxml = null;
setTimeout(this.ref+'.loadRSS();', this.delay);
}
document.addEventListener("DOMContentLoaded", createFunctionReference(this, this.initRSS), false);
}
// An example implementation:
var MyNews = new RSSFeed("MyNews", "newsfeed.php", "newsdiv", 5000);
What can be done to reduce memory leakage and not freeze my clients’ computers?