DOMContentLoaded for IE, Safari, everything, without document.write

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.

19 Responses to “DOMContentLoaded for IE, Safari, everything, without document.write”

  1. jQuery are going in a slightly different direction; see:

    http://groups.google.com/group/jquery-dev/browse_thread/thread/517dd87b61515162

    Any use?

    Robin
  2. Interesting. I hadn’t seen John’s new approach to this. Yo, John, how’s testing going on the insert-into-the-document approach?

    sil
  3. 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
  4. 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…

    sil
  5. 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.

    sil
  6. 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?

    Stephen Stchur
  7. Oops, my bad; stupid suggestion. Ignore me ;-)

    Stephen Stchur
  8. [...] 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) [...]

    Infovore » links for 2007-09-26
  9. 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 Perini
  10. 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?

    sil
  11. 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

    Diego Perini
  12. [...] 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) [...]

    napyfab:blog» Blog Archive » links for 2007-09-27
  13. 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..

    Tercüme bürosu
  14. [...] 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. [...]

    Sonata the Server » Blog Archive
  15. [...] 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 News » Blog Archive » window.onload: another solution to get it going
  16. [...] 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 [...]

    Future of Web Apps Conference
  17. [...] DOMContentLoaded for IE, Safari, everything, without document.write [...]

    Does setTimeout solve the DOMContentLoaded problem? | Muffin Research Labs by Stuart Colville
  18. [...] 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 [...]

    Future of Web Apps Conference | Ruby on Rails blog archives from around the web
  19. [...] you need reliable standalone “DOMContentLoaded” JavaScript function, take a look at the shortloaded by famous Stuart [...]

    maratz.com » Blog Archive » FOWA Expo random bits

Leave a Reply

OpenID is a decentralised authentication system. If you use LiveJournal or Vox you already have an OpenID; just use the URL of your homepage there. See also how to get yourself an OpenID.