We have now had, for a while, a way of emulating the “DOMContentLoaded” event across all the main browsers. For those of you who don’t know what I’m talking about, a web browser fires an event, “load”, when a page finishes loading, and JavaScript can attach code to that event which will then run once the page has loaded. However, if there are big images or other slow-loading things in the page then the code gets delayed until after they’ve finished loading too; this is annoying, because most DOM scripting doesn’t actually need the images to be loaded, and so the delay is unnecessary. Opera and Mozilla fire a “DOMContentLoaded” event which runs after the page has loaded but before all the slow images and applets and Flash movies need to load, which is perfect. IE and Safari don’t fire such an event, but it’s been possible to do IE and Safari-specific things to make it happen. (In Safari you check document.readyState, in IE you document.write a <script> element with defer set. See Dean’s writeup.) If you’re using a JavaScript library of some sort (jQuery, Prototype, Mootools, whatever) then all this complexity gets wrapped up for you and you don’t have to worry about it, but if you’re writing stand-alone scripts (like my sorttable), which don’t depend on a library, then this is more of a problem; you have to include a big swathe of boilerplate code to emulate the DOMContentLoaded event. Recently, Hedger Wang provided an alternative approach for IE that doesn’t rely on document.write, which is rather neat. So, it should be possible to combine the existing Safari method, Opera and Mozilla’s DOMContentLoaded support, and Hedger’s IE approach into a short bit of boilerplate code that can be dropped into your standalone script. And indeed it is. See a simple demo, and more importantly, here is the short version of the code:
(function(i) {var u =navigator.userAgent;var e=/*@cc_on!@*/false; var st =
setTimeout;if(/webkit/i.test(u)){st(function(){var dr=document.readyState;
if(dr=="loaded"||dr=="complete"){i()}else{st(arguments.callee,10);}},10);}
else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
document.addEventListener("DOMContentLoaded",i,false); } else if(e){ (
function(){var t=document.createElement('doc:rdy');try{t.doScroll('left');
i();t=null;}catch(e){st(arguments.callee,0);}})();}else{window.onload=i;}})(init);
The init on the last line is the name of your “init” function; the one that you want to call on page load. (It could be an inline function if required.) Simply copy those 7 lines into your standalone script and change the name of the init function to be your init, and you’re good to go on all browsers. Remember that if you’re already using a JavaScript library then you don’t need this, but if you’re not then it’s simpler than the current swathes of code, and less heavy than depending on a library just to get access to cross-browser onload event handling.
jQuery are going in a slightly different direction; see:
http://groups.google.com/group/jquery-dev/browse_thread/thread/517dd87b61515162
Any use?
Interesting. I hadn’t seen John’s new approach to this. Yo, John, how’s testing going on the insert-into-the-document approach?
The ‘short version’ of the code has a serious problem. None of your variables are declared with a var statement; They are all implicit globals, which is terrible practice.
henrah: oops. I took all the var statements out when I was making it shorter and forgot to put them back in again. I’ll fix that…
Right, now fixed to include var statements again. Of course, this has buggered up the beautiful bricktext nature of the original, but such is life.
Instead of the try/catch, wouldn’t it be cheaper to to check:
if (typeof t.doScroll !== ‘undefined’)
{ i(); t = null; }
else
{ st(arguments.callee, 0); }
Wouldn’t the try/catch be more costly?
Oops, my bad; stupid suggestion. Ignore me
[...] as days pass by » Blog Archive » DOMContentLoaded for IE, Safari, everything, without document.write “it should be possible to combine the existing Safari method, Opera and Mozilla’s DOMContentLoaded support, and Hedger’s IE approach into a short bit of boilerplate code that can be dropped into your standalone script.” Nice! (tags: javascript programming development dom scripting ie) [...]
I can’t see my name cited…nor the URL to the original code.
However I suggest you use the original solution:
http://javascript.nwbox.com/IEContentLoaded/
or, for a cross browser solution:
http://javascript.nwbox.com/ContentLoaded/
On IE this solution relies on the “documentElement” to test the doScroll(‘left’). The document will not scroll !!!
Diego Perini
Diego: sorry, I just linked through to Hedger’s page, which cites your original work. What do you think is better about your original solution rather than Hedger’s, so I can compare?
Stuart,
his modifications to my original code are nonsense.
He just introduced problems and didn’t solve any issue.
First of all, he his not using “document.documentElement”, he just start creating extra non needed nodes; from his explanations he was afraid the document will scroll after every page load so wanted to use a fake element…
Then every cycle of his “setTimeout” will create a new element and consume memory, and with an interval of “0″ milliseconds, hundreds of them will be created, he didn’t really understand the code he was trying to modify, nor what his modification will produce.
My original code (test cases) also take care about ensuring that the “init()” function is called only once and before “window.onload” by combining the above trick with an “onreadystatechange” event. This extra safe code is normally used during “bfcache” refresh and F5/Refresh…
I believe however that Hedger is a nice guy, he surely didn’t want to do all that bad intentionally…
Diego Perini
[...] as days pass by » Blog Archive » DOMContentLoaded for IE, Safari, everything, without document.write (tags: javascript dom web programming ie domcontentloaded onload ajax development html) [...]
Opera and Mozilla’s DOMContentLoaded support, and Hedger’s IE approach into a short bit of boilerplate code that can be dropped into your standalone script..
[...] characters. There is another solution that is as short as this one, done by Stuart Langridge (see DOMContentLoaded for IE, Safari, everything, without document.write). However, for whatever reason his solution doesn’t seem to always work in Internet Explorer. [...]
[...] characters. There is another solution that is as short as this one, done by Stuart Langridge (see DOMContentLoaded for IE, Safari, everything, without document.write). However, for whatever reason his solution doesn’t seem to always work in Internet Explorer. I [...]
[...] Javascript Widgets. Instead of doing a document.write, Dopplr uses the shortloaded Javascript snippet to load Javascript-generated content into a div on the client’s site. So [...]
[...] DOMContentLoaded for IE, Safari, everything, without document.write [...]
[...] Javascript Widgets. Instead of doing a document.write, Dopplr uses the shortloaded Javascript snippet to load Javascript-generated content into a div on the client’s site. So [...]
[...] you need reliable standalone “DOMContentLoaded” JavaScript function, take a look at the shortloaded by famous Stuart [...]
I was going to point out what Diego said, isn’t the 0ms time going to be costly in terms of memory or performance (intense looping)?
Also, was thinking it would be helpful to see timing information as it relates to the window load event fires, when the document has a height greater than 0, etc.
A belated thanks for the post!
[...] http://www.kryogenix.org/days/2007/09/26/shortloaded [...]
[...] due to the hack used for IE (DOMContentLoaded is not a native function in IE 6, 7, or 8 and thus hacks were [...]
by the way what is i function?: as we see ‘function(i)’.
Hi,
I really like your solutions, i came across you site a couple of weeks ago, because as i worked on an application i needed a way to execute certain scripts when the dom was ready.
After using your script, reviewing John Resig Safari solution and Diego Perini(http://javascript.nwbox.com/IEContentLoaded/) approach for IE i started to test different approaches…
I consider myself an almost intermiediate programmer, so this is what i came up with:
function isDOMready() {
try {
window.scrollTo(0,0);
domStatus();
} catch(e) {
setTimeout(‘isDOMready();’, 0);
return;
}
function domStatus(status) {
alert(‘DOM ready’);
return;
}
}
I have tested it in different browsers and it seems to work, please tell me if this is correct, or if im completely offtopic, sorry for my english.
Raimundo Araujo – http://www.codigopixel.net
Hi, thanks for the nice post.
I am trying something with iframes http://jsfiddle.net/MXsww but not working. Can you please help?
Nice post, but the demo doesn’t do much since the hotlinked image has been removed. Try another one?
I don’t know if you will still read this, but shouldn’t it be “arguments.caller” with “r” at the end not “e”