I’m currently working on AJAXifying an existing site. A problem I’m having is that some pages require extra js to be loaded. Loading the js is easy - just use js to add a script tag to the page pointing at the js file to be loaded.
The issue comes when moving to a page that doesn’t need that previously loaded js - you can remove the script tag, but the js from that file will stay loaded in the browser.
A possible solution I thought would be to ensure that everything in the loaded js file is encapsulated, and when that file is removed, then remove any event handlers it has assigned. That way there will be no references left to anything in the previously loaded js file, and the gc should clean it up.
However, if I run a test in IE and debug using Developer Tools, if I add the js, remove it, then add it again, I see the added js file twice in the sources list (and more if I repeat the removing and adding process more times).
I’m not really au fait with js profiling to determine whether this is an actual issue or not.
Example page: http://www.iliveinabin.com/AJAX-test-del/
I guess my actual question would be, is what I’m doing sensible, or does anyone have a better suggestion?
Thanks
Dave
Main js included in the page that loads and removes the additional js file:
function loadScript(e)
{
if (e.preventDefault) {
e.preventDefault();
}
if (!document.getElementById('ajax')) {
var script = document.createElement('script');
script.src='./ajax.js';
script.id = 'ajax';
//if we're adding a new script we need to wait for it to finish loading before
//triggering the DOMContentLoaded event
script.onload = triggerDOMContentLoadedOnScriptLoad;
document.body.appendChild(script);
} else {
despatchEvent('DOMContentLoaded', document);
}
function triggerDOMContentLoadedOnScriptLoad(e)
{
despatchEvent('DOMContentLoaded', document);
}
return false;
}
function removeScript(e)
{
if (e.preventDefault) {
e.preventDefault();
}
var script = document.getElementById('ajax');
if (script) {
despatchEvent('scriptRemoved', script);
script.parentNode.removeChild(script);
}
return false;
}
JS file that is loaded / removed as needed (ajax.js):
(function()
{
console.log('ajax.js loaded');
var documentLoaded = (function()
{
var longstr='';
return function(e)
{
for (var chars = 'abcdefghijklmnopqrstuvwxyz ', i = 0; i<1000000; i++) {
longstr += chars.charAt(Math.floor(Math.random() * (27 - 1)) + 1);
}
alert(longstr.length);
}
})();
document.addEventListener('DOMContentLoaded', documentLoaded, false);
document.getElementById('ajax').addEventListener('scriptRemoved', cleanup, false);
function cleanup(e)
{
document.removeEventListener('DOMContentLoaded', documentLoaded, false);
document.getElementById('ajax') && document.getElementById('ajax').removeEventListener('scriptRemoved', cleanup, false);
console.log('ajax.js removed');
}
})();
Edit: After amending my code slightly and doing a bit of very rudimentary testing, it appears that the gc frees up the used memory in FF once the script and handlers have been removed (though it can take a minute or two before the gc runs). In IE it looks like the memory stays allocated to IE, but IE will re-use this memory.