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?
Posted by Robin on September 26th, 2007.
Interesting. I hadn’t seen John’s new approach to this. Yo, John, how’s testing going on the insert-into-the-document approach?
Posted by sil on September 26th, 2007.
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.
Posted by henrah on September 26th, 2007.
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…
Posted by sil on September 26th, 2007.
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.
Posted by sil on September 26th, 2007.
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?
Posted by Stephen Stchur on September 26th, 2007.
Oops, my bad; stupid suggestion. Ignore me ;-)
Posted by Stephen Stchur on September 26th, 2007.
[...] 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) [...]
Posted by Infovore » links for 2007-09-26 on September 27th, 2007.
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
Posted by Diego Perini on September 27th, 2007.
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?
Posted by sil on September 27th, 2007.
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
Posted by Diego Perini on September 27th, 2007.
[...] 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) [...]
Posted by napyfab:blog» Blog Archive » links for 2007-09-27 on September 28th, 2007.
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..
Posted by Tercüme bürosu on October 30th, 2007.
[...] 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. [...]
Posted by Sonata the Server » Blog Archive on December 29th, 2007.
[...] 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 [...]
Posted by Javascript News » Blog Archive » window.onload: another solution to get it going on January 3rd, 2008.
[...] 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 [...]
Posted by Future of Web Apps Conference on January 15th, 2008.
[...] DOMContentLoaded for IE, Safari, everything, without document.write [...]
Posted by Does setTimeout solve the DOMContentLoaded problem? | Muffin Research Labs by Stuart Colville on February 15th, 2008.
[...] 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 [...]
Posted by Future of Web Apps Conference | Ruby on Rails blog archives from around the web on March 26th, 2008.
[...] you need reliable standalone “DOMContentLoaded” JavaScript function, take a look at the shortloaded by famous Stuart [...]
Posted by maratz.com » Blog Archive » FOWA Expo random bits on April 15th, 2008.
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!
Posted by Dave Artz on July 3rd, 2008.
[...] http://www.kryogenix.org/days/2007/09/26/shortloaded [...]
Posted by Javascript’s window.onload preceded « Will Fris’s WordPress Weblog on July 29th, 2008.
[...] due to the hack used for IE (DOMContentLoaded is not a native function in IE 6, 7, or 8 and thus hacks were [...]
Posted by JQuery Performance Rules - Speed Up JQuery JS! on April 9th, 2009.