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?
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 …)