When Does jQuery Consider The DOM Loaded And Can I Use It Beforehand

Posted March 15, 2007 at 2:30 PM by Ben Nadel

Tags: Javascript / DHTML

I really like the idea of making your XHTML markup very structure and informative and letting the Javascript events be bound via jQuery once the DOM has loaded. But, to be honest, that is not always something that is practical. Think about a navigational system; I don't want the document to finish loading to make sure that navigation-related Javascript works.

Before I get ahead of myself, I decided to figure out when the jQuery framework things the DOM is fully loaded. This should be when all the HTML has been sent to the client, but, worth a check. Here is a rather simple test that forces the thread to sleep right before it is done:

  • <html>
  • <head>
  • <title>jQuery Document Ready Test</title>
  • <script type="text/javascript" src="jquery-latest.pack.js"></script>
  • <script type="text/javascript">
  •  
  • // When the document loads, write the date to the
  • // paragraph with ID "end".
  • $(
  • function(){
  • $( "#end" ).text(
  • (new Date()).toString()
  • );
  • }
  • );
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • JQuery Document Ready Test
  • </h1>
  •  
  • <!--- Let Javascript write this one. --->
  • <p id="start">
  • <script type="text/javascript">
  • document.write( new Date() );
  • </script>
  • </p>
  •  
  • <!---
  • Leave this one blank for now. JQuery will fill this
  • one in once the document loads.
  • --->
  • <p id="end">
  •  
  • </p>
  •  
  •  
  • <!---
  • Flush the document to make sure the above Javascript can
  • fire before we force the thread to sleep.
  • --->
  • <cfflush />
  •  
  •  
  • <!--- Sleep the thread for three seconds. --->
  • <cfset objThread = CreateObject(
  • "java",
  • "java.lang.Thread"
  • ).CurrentThread().Sleep(
  • JavaCast( "long", (3 * 1000) )
  • ) />
  •  
  • </body>
  • </html>

Running this page gives us the following output:

JQuery Document Ready Test

Thu Mar 15 2007 14:23:09 GMT-0400 (Eastern Daylight Time)

Thu Mar 15 2007 14:23:12 GMT-0400 (Eastern Daylight Time)

As you can see, the "End" time is three seconds behind the "Start" time. Since we use CFFlush to make sure the first one is written immediately, we can clearly see that jQuery considers the DOM fully loaded once all the HTML has been sent to the client. Good to know, but somewhat obvious.

Well, even though jQuery waits until all the HTML is there to run the $( fn{} ) methods, does that mean we have to wait for the DOM to load before we use jQuery features? In this test, we run a very similar page, but this time, we replace the $( fn{} ) method with an inline jQuery request:

  • <html>
  • <head>
  • <title>jQuery Document Ready Test</title>
  • <script type="text/javascript" src="jquery-latest.pack.js"></script>
  • </head>
  • <body>
  •  
  • <h1>
  • JQuery Document Ready Test
  • </h1>
  •  
  • <!--- Let Javascript write this one. --->
  • <p id="start">
  • <script type="text/javascript">
  • document.write( new Date() );
  • </script>
  • </p>
  •  
  • <!---
  • Leave this one blank for now. JQuery will fill this
  • one in when we ask it to.
  • --->
  • <p id="end">
  •  
  • </p>
  •  
  •  
  • <script type="text/javascript">
  •  
  • // Get jQuery to fill in the "End" paragraph before
  • // the document has finished loading.
  • $( "#end" ).text(
  • (new Date()).toString()
  • );
  •  
  • </script>
  •  
  •  
  • <!---
  • Flush the document to make sure the above Javascript can
  • fire before we force the thread to sleep.
  • --->
  • <cfflush />
  •  
  •  
  • <!--- Sleep the thread for three seconds. --->
  • <cfset objThread = CreateObject(
  • "java",
  • "java.lang.Thread"
  • ).CurrentThread().Sleep(
  • JavaCast( "long", (3 * 1000) )
  • ) />
  •  
  • </body>
  • </html>

Running this page gives us the output:

JQuery Document Ready Test

Thu Mar 15 2007 14:26:07 GMT-0400 (Eastern Daylight Time)

Thu Mar 15 2007 14:26:07 GMT-0400 (Eastern Daylight Time)

As you can see, the Javascript write and the jQuery text() method fire one directly after the other. The thread sleep directly after that proves that we can access jQuery features before the DOM is fully loaded.

Now, is it a good idea to do this? Not sure. I think that as long as all the DOM elements in question have already been loaded then you are totally fine. I could certainly imagine doing this some sort of "Ready" function right before the primary page content loads to make sure all pre-primary-content Javascript is hooked up in case the content itself takes a long time to render.



Reader Comments

Mar 15, 2007 at 5:26 PM // reply »
4 Comments

Interesting find. This is particular useful for code that as to run before the user can see anything at all, especially when the page isn't send to the browser in one big chunk.

On the other hand, I can hardly imagine a case where adding event handlers like clicks to the document can't wait for jQuerys DOM ready event.

I'll give it a try on a particular problem that could benefit from a faster "DOM ready".


Mar 15, 2007 at 5:35 PM // reply »
11,241 Comments

I am not worried about the "everyday" examples. But, if you have a site that has constant navigation and variable content (pretty much every site), you have to imagine that every now and then you might have a page whose content takes a long time to load (maybe someone wrote a crappy query and they are accidentally building a table that has 1000 rows)... whatever the reason, as long as it is always works, it seems like a good safety measure to apply events as they can be....

Of course, I am just getting into jQuery, so I might be way off.


Mar 15, 2007 at 9:25 PM // reply »
28 Comments

Hey Ben, I'm glad Joern chimed in here. He's the team lead for the jQuery Core team so definitely offer him up feedback. He's a cool dude and an awesome developer.


Mar 16, 2007 at 7:26 AM // reply »
11,241 Comments

Hey, it's my pleasure to be messing with jQuery.


Mar 17, 2007 at 12:23 AM // reply »
46 Comments

I know of lots of pages that load the header and then access some slow ass content management system and take forever to load up the rest of the content.

There is nothing wrong with having the jQuery to bind the nav included after the nav loads.

The rules are exactly like regular javascript. You cant access something that doesn't exist. Once it's in the DOM then you can play with it.

If you know it might be a delay between NAV and rest of page, then for sure, bind those suckers early.

Glen


Mar 17, 2007 at 11:36 AM // reply »
11,241 Comments

Even with the early bind, I think it is still a hell of a lot more elegant that have a lot of JS wrapped up in the HTML markup.


Mar 18, 2007 at 12:50 PM // reply »
46 Comments

I actually thought of this while sleeping. It probably has bugs, I havent tested, but its in the ballpark.

Assuming you had your header in an include file....the include should look something like:

<ul class="header">
<li title="Home">Home</li>
<li title="Products">Products</li>
<li title="Support">Support</li>
<ul>

Then on the specific page: (let's say the product page)
<inlude header.cfm>
<script>
initHeader("Products");
<script>

Then the jQuery would be:
function initHeader(target) {
var onLink = $("ul.header li[@title=" + target + "]")
$(onlink).addClass("on");

$("ul.header li").hover(function(){
$(this).addClass("hover");
},function(){
$(this).removeClass("hover");
});

$("ul.header li").bind("click", function(){
navigate()
});

}

function navigate() {
var newPage = $(this).attr("title");
location.href = "http://www.mysite.com/" + newPage + ".cfm"
}

Anyway, the point is, the header wouldn't have any information about anything.


Mar 19, 2007 at 7:33 AM // reply »
11,241 Comments

I would feel OK doing something like that. I think it still keeps the HTML very clean.

My only nit-picky thing (and I know this was just a demo), but I wouldn't bind click events for navigation. Navigational links should probably exist with or without Javascript.


bob
Nov 19, 2011 at 11:02 PM // reply »
1 Comments

CreateObject(
"java",
"java.lang.Thread"
).CurrentThread().Sleep(
JavaCast( "long", (3 * 1000) )
)

should be written as

CreateObject(
"java",
"java.lang.Thread"
).Sleep(
JavaCast( "long", (3 * 1000) )
)

since sleep is a static method


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 7:52 AM
Nested Views, Routing, And Deep Linking With AngularJS
Hi, Just a quick thank you. As it happens, for my own purposes, the pending ui-router work being done in native angular is likely the one I'll adopt, but your exploration, code and documentation of ... read »
May 22, 2013 at 4:43 AM
How Do You Use The ColdFusion CFParam Tag?
'<cfparam>' or 'isDefined()and <cfset>' performs the same task.Is there any difference? ... read »
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools