Skip to main content
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Curt Gratz
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: Curt Gratz

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

By on

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.

Want to use code from this post? Check out the license.

Reader Comments

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".

15,674 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.

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.

55 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

15,674 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.

55 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.

15,674 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.

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

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel