For those of you who are familiar with JavaScript libraries, you are probably at least a little bit aware that there is an “event” that occurs during the loading of a page which abstractly represents the point in time in which the browser has fully processed the structure (aka, the “DOM”) of the HTML document being displayed.

This “event” is separate from (and ostensibly noticeably earlier than) the more familiar “onload” event, whose defined behavior means that all of the page’s initial resources have fully loaded — before “onload”, there is an earlier state at which things (such as images and styles) are still loading, but the basic plan or skeleton of the page is now known and understood and the browser knows what to expect.

This “event” is, in some browsers, an actual event, in other browsers it’s a state which can be passively observed, and in some browsers, it has to be divined by examining the alignment of the stars and taking into account the wind speed and gravitational pull of various heavenly bodies, divided by the…

You get the point, there’s an “event” that the browsers try (and some do better than others at this attempt) to expose for when the DOM is ready, which I will now conveniently and uncreatively call “DOM-ready”.

So what if the DOM is ready or not?

Let me make sure that you understand the importance of DOM-ready. In some cases, if you have JavaScript logic that tries to modify the DOM of your page before this DOM-ready event has occured/passed, you can wreak havoc with that browser, and in some cases, cause a fatal error and browser crash.

Think of it this way: if i’m standing on one foot, precariously balanced, and trying to pull on a sock over my bare foot, and my wife comes along and tugs on the rug I’m standing on, am I likely to get that sock put on successfully? Am I even likely to stay standing? Probably not.

So, it’s wise to make sure that you don’t take any actions which could adversely affect the browser’s ability to get his sock on, at least if you don’t want him to fall over. And that’s why we have the concept of DOM-ready — to make sure that you don’t manipulate the DOM too early.

Moreover, the major JS frameworks (for that matter, most of even the minor JS tools out there) all provide ways for you queue up code to be executed at some later time, that time being when the framework is able to detect that the event has occured and that it’s now safe for your code to go about the business of changing things.

The frameworks all take care of that mess for me, right?

Ahh, don’t we wish that were completely true. If it were, this post would be somewhat pointless, and you’d instead be enjoying eating a pizza or watching re-runs of Grey’s Anatomy.

Alas, the world is not that simple. There’s a little known, but I believe important, problem with the way DOM-ready detection is accomplished by the frameworks in a cross-browser way. I’m not going to bore you with all the details of just how this detection occurs, but let’s just say it gets a little hackish in some cases.

For the lion-share of use cases, the DOM-ready detection that the current framework versions employ is acceptable, at least for all the browsers that most of us really care about working correctly. If you’re still worried about Netscape 3.0 though, you’re on your own… good luck!

But, a subtle problem creeps in when you step outside the normal set of uses cases — those being where you simply include a <script> tag at the top (or bottom, if you’re really clever) of your HTML document that loads your framework of choice (let’s say “jquery.js” for the purposes of this post).

Let’s say you have a mashup where you are pulling together multiple websites, and maybe jQuery is not guaranteed to already be present on the page. “No problem!” you say, because you know how to load a script file on-demand, so you’ll just fire off a request to do so, and wait for jQuery to be present before you proceed to make calls against it (and, of course, then use it to change the page!)

Or, let’s say you have a bookmarklet that people can use to popup some nifty little widget in their page of choice, and again, you want to make sure that jQuery is present for your code to utilize. Again, we’ll just load jQuery on-the-fly, and we should be good to go, right?

Or even better, let’s just say you’ve got a really complex application, which loads different scripts into the page at different times depending on the state of what the user does. Yet again, you may need to fetch jQuery at some point well after the initial page loading occured.

There’s yet another use-case, which is actually the one that I ran into that caused me to discover this issue several months ago. If your page uses a script loader, such as LABjs, the one I wrote in cooperation with Steve Souders (of Yahoo! and Google fame), you have to be aware of how certain scripts, notably the frameworks, do their DOM-ready detection and how this applies when the script is loaded dynamically.

Because script-loaders remove the “blocking” nature of script loading that normal <script> tags provide, it is actually quite possible to get into a situation where you load a script, like “jquery.js”, but the rest of the page is so well optimized that the DOM-ready event passes before jQuery arrives. You may very well not intend this to occur, but it can, and worse yet, it can happen as a race-condition, where it happens sometimes, and not others.

(… more …)

Pages: 1 2

This entry was written by getify , posted on Saturday November 21 2009at 10:11 am , filed under JavaScript and tagged , , , , . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

10 Responses to “Why DOM-ready still sucks”

  • codylindley says:

    So, if I never use the custom DOM ready event and place my all my scripts before the closing body element then I shouldn’t have to worry about the issues with labjs and jquery. Correct?

  • getify says:

    @codylindley — that is true, as long as none of the scripts you are loading care about $(document).ready(…), jQuery is perfectly safe to use with LABjs!

    It’s just $(document).ready(…) usage is so common with jQuery pages that it’s easier to assume it is being used and be cautionary, than to assume the opposite and have lots of weird race-condition gotchas. :)

  • Buzz says:

    you may need to fetch jQuery at some point well after the initial page loading occured, right? I still getting errors, dunno why.

  • getify says:

    Make sure if you’re trying to load jQuery dynamically, that it’s at least 1.4+. Previous versions of jQuery didn’t support that use case.

  • Daniel says:

    I just wonder if I use window.onload to detect the Dom ready, is there any issues works with Labjs?

  • Great examples buddy. I specially liked the example about having one leg in the air and wife pulling the carpet ….

    Before this, I was thinking that onload is the best method to use. But thanks to your good article, now I have a clear understanding.

    Thanks.

  • brothercake says:

    All you’re really saying is that DOM-ready and window.onload are not directly interchangeable, because the states they observe are different. And that’s true, yes. And that affects script loaders, IFRAME and OBJECT based RPC scripting, and other things.

    That doesn’t mean DOM-ready sucks, it just means you’ve learnt something about it that you didn’t know before :-)

  • getify says:

    @brothercake — actually, I think you really missed the point of this point. the point simply put is, lots of devs queue up code to wait for DOM-ready, but if the logic they use to detect DOM-ready comes after DOM-ready has happened (regardless of window.load), then their queued code will never run. Back in 2009 when this article was written, some of the browsers didn’t have a way to detect if the event had already passed (that is, is the current page’s DOM already “ready”?). NOW they all do, so this whole article is moot. But it was a real problem 3 years ago at the time of writing.

  • brothercake says:

    Yeah I did miss that. Perhps because you spent most of the first page describing the DOM ready state as a mess, when it isn’t any such thing, only the way certain libraries apparently used to deal with it.

    Given that, the article’s title is misleading, and the source of my misdirection.

    I only found this post at all because it was high in search results for “domReady”. Perhaps you might clarify the start of the article, to say that it isn’t really about DOM ready at all.

  • getify says:

    @brothercake — I appreciate your feedback but I stand-by the title (it IS all about DOM-ready, and how hard, back then, it was to detect, it if you’re not listening at the time it happens), and I also stand by the subject and conclusions of the article at its time (2009).

    I don’t know if you were doing such types of scripting stuff back then, as I was heavily, but I have lots of experience from back then which backs up what I claimed here. It was all very valid back then, but things are in a very different state now (all browsers have document, so most of the claims made here are historical and no longer applicatble.

    If you’re interested in reading some actual history behind the drama around DOM-ready detection from as far back as 2007, here’s a long but informative bug thread discussing how `document.readyState` finally made it into FF after several years and many ups and downs.

    https://bugzilla.mozilla.org/show_bug.cgi?id=347174

Leave a Reply

Consider Registering or Logging in before commenting.

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Notify me of followup comments via e-mail. You can also subscribe without commenting.