PPK’s article for alistapart entitled "JavaScript Triggers", describes how to separate behavior from content by attaching event handlers at page load time. Jim Ley points out that the window’s onload event is sometimes too late to do this. Although I think he is right, it is only a problem for pages with lots of graphical content.
The problem is that the window’s onload event fires after all page content is loaded. That includes images and other binary content. If a page has lots of images (or one big one), then the onload event may not fire for several seconds after the HTML content is visible. If a menu is animated by JavaScript, then it would not be active immediately (unlike a CSS based menu).
Internet Explorer (and Opera) provide additional properties and events that provide a better indication of the state of the document. On these platforms, a document’s readyState is set to "interactive" when the document’s HTML has been loaded and parsed. This is the event you really want! It occurs immediately after the DOM has been built and doesn’t wait around for images to catch up.
A while back I did some experiments to see the order of events for page load. Bear in mind that Mozilla browsers don’t support onreadystatechange, so the results won’t mean much on that platform. Internet Explorer has the most revealing results.
Update. I’ve posted a follow-up to this post with more information
on DOMContentLoaded and a way to imitate this event for Internet Explorer.
Comment: #1.
This is interesting; I’ve come across a related issue while using your very useful “mozilla behaviours” XML-translation-metamorphosis script. I noticed that at some point you fire off the event “ondocumentready” immediately because Mozilla doesn’t support it. I have an htc file that colours table rows in an odd-even pattern, and the event is fired “ondocumentready” - with the side effect that in Mozilla, for large tables in slow connections only part of the table gets painted (the “for-each-row” loop starts before all rows are there).
I wonder if you have any clever suggestions?
Comment: #2.
Hi Nelson. I was thinking of faking the
ondocumentreadyevent for Mozilla by using XBL somehow but I haven’t had a chance to experiment.There is a new version of moz-behaviors awaiting release. It has better support for
ondocumentreadyandoncontentreadybut it is still not perfect.If anyone knows how to detect when the document has finished parsing on Mozilla please let me know!
Comment: #3.
Dean,
There was some discussion about this on the Greasemonkey mailing list.
Aaron Boodman (the author of Greasemonkey) said:
Is this what you are looking for?
Prakash
P.S. Thanks for all the work you’ve done.
Comment: #4.
Thanks Prakash!
That’s exactly what I’m looking for!
Comment: #5.
Comment: #6.
Abdul, try this:
function test() { alert("Success!"); }; document.addEventListener("DOMContentLoaded", test, false);Comment: #7.
Comment: #8.
if (document.readyState == "interactive"){ countLinks(); }If I call the same function from an onreadystatechange event handler the function now only fires once the document’s state has changed to “complete” (which is too late) defeating the purpose of the ‘preload’.if (document.readyState == "interactive"){ document.onreadystatechange = countLinks; }Which is a shame since the Mozilla equivalent works a treat.Comment: #9.
readyStatething myself now…bodyand trap theondocumentreadyevent.Comment: #10.
Comment: #11.
Comment: #12.
DomContentLoaded and ondocumentready attached via an htc would seem to be half the battle, but…. Have any ideas on detecting support for DomContentLoaded? The second one is easy enough to handle by testing for document.body.addBehavior, but I can’t figure out any way to detect the first.
I’d rather not have to fall-back to my polling alternative when there is such a suitable event, but I’d have to for cross-browser support if I couldn’t figure out how to detect it. (If it isn’t obvious I’m working on a xbrowser method of handling a DomContentLoaded-esque event - and yes, I know I’m not the first).
Comment: #13.
Tim - I intend to publish an update to this post fairly soon. I’ll answer your question and show some alternative techniques too. Stay tuned!
Comment: #14.
Cool, thanks Dean. I’ll hold off on getting too fancy until then.
I guess for now I’ll stick with your cssQuery fired off by either brothercake’s DOM function (maybe passed a silly id=”lastChild”), the basic xbrowser onload binding, or whatever the simplest use of domcontent and readystate falling back to the onload I can come up with, for my event-binding needs.
I’m excited to see what you’re going to post on this (well, I have been since hearing you were planning a summary of it all after @media, but decided to start looking into it more in impatience
) and how slick we can get armed with that knowledge.
Comment: #15.
Any news on this? I’m still waiting for the best and most concise ‘onDOMLoad’ event function - if anybody is the man to write it then it’s you Dean. I’ve tried using a setTimeout to check for the DOM tree and it works pretty well (even in Mac IE), however my function is simple a replacement for window.onload and isn’t that clever at all (plus it seems to fire the onload event too many times).
I tried to post the js code but it kept saying ‘not well formed xhtml’ even tho it was in in pre tags
Comment: #16.
// to use simply assign an onload property like so: DOM.onload = fnc or DOM.onload = function(){ code } DOM = { onload: function(){ alert('DOM Says Hi!') }, check: function(){ if(document && document.getElementsByTagName('BODY')){ DOM.onload(); clearInterval(DOM.interval) }}, interval: setInterval('DOM.check()',10) }Comment: #17.
OK guys, I’m moving this nearer to the top of my “To Do” list. It will probably be cross-posted on the WaSP DOM Scripting site too. I just got back from a mini-break in Edinburgh and have some catching up to do. But there is clearly a demand for this information so I’ll do my best to satisfy demand.
Comment: #18.
Of course, this will depend largely on what you end up posting, but the more I look into it the more I’m leaning towards just making a constructor (and the .htc of course) that uses DomContentLoaded and ondocumentready semi-blindly (with the appropriate checks to not throw an error) and let’s everyone else deal with waiting on the onload. Do some fancy footwork about how you attach all of the above through a consistent point, and then just keep track of wether this has been run yet.
If either of the pre-onload calls went through, you’ve marked your uber function as already run and when the onload fires it just exits (and of course, marks it as run in case something causes either event to fire after the onload - like maybe Safari supporting DomContentLoaded later, but in a different way).
Comment: #19.
If I may be so bold to offer up a solution I released a few months ago. It doesn’t match up exactly with what some of you are looking for, but may be of use to others.
onDOMload is similar to brothercake’s DOM function, but looks for ids/tags/classes of elements on which to run the desired code. So it can be run on a single element (id) or multiple elements (class/tag).
Hope this is helpful to some, and I’m not out of line posting to my own stuff. Found this discussion by searching for “ondomload” in Google, which found Jon B’s mention of the word/concept in post 15… so figured I’d offer up my script of the same name.
But I am curious to see what dean is able to come up with as well
Comment: #20.
Hi, Dean
the detection of readyState works for me on http://www.hedgerwow.com/360/dhtml/before_onload.php.
May I ask that what`s your concern about the latency of detection of readySate in this case?
Thanks for your help.
Regards.
Comment: #21.
Hedger - I don’t know why
readyStateis unreliable. The only thing I can say is that sometimes it works and sometimes it doesn’t. Thecompletestate is the same aswindow.onloadand theinteractivestate is usually OK for small pages but doesn’t always imply that the DOM is complete. This is especially true if you are usingdocument.writeto generate content.Comment: #22.
Really works well. Thanks!. But IFRAME loaded very slowly in Mozilla.
Comment: #23.
Comment: #24.
Comment: #25.
Hi, DOMContentLoaded not works when the response is a application/pdf file. What I Do?
Comment: #26.
Comment: #27.
Comment: #28.
In Internet Explorer 7, when I do an alert(document.readyState) through window.onload, it shows “interactive”. Has anyone experienced this before?