Don’t let jQuery’s $(document).ready() slow you down
jQuery, Performance, UI By Dave Ward. Posted August 18, 2010jQuery’s $(document).ready() event is something that you probably learned about in your earliest exposure to jQuery and then rarely thought about again. The way it abstracts away DOM timing issues is like a warm security blanket for code running in a variety of cold, harsh browser windows.
Between that comforting insurance and the fact that deferring everything until $(document).ready() will never break your code, it’s understandable not to give much thought to its necessity. Wrapping $(document).ready() around initialization code becomes more habit than conscious decision.
However, what if $(document).ready() is slowing you down? In this post, I’m going show you specific instances where postponing startup code until the document’s ready event slows perceived page load time, could leave your UI needlessly unresponsive, and even causes initialization code to run slower than necessary.
Example: live()
One of the most popular uses for jQuery’s live() is to maintain event handlers on elements that are dynamically created and destroyed over time. Instead of juggling traditional bind() handlers in response to those changes, live()’s event delegation allows you to declare handlers once up-front. Whether targeted elements exist at declaration time, or in the future, one live() handler will apply to them all.
Imagine that we have an application with several slideToggling sidebar blocks which may be dynamically added and removed while the user interacts with the page. You’ve probably seen live() used like this to simplify handling those future changes:
<html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> <!-- The sidebar event delegation is not registered "here"... --> $(document).ready(function () { $('#Sidebar h3').live('click', function () { $(this).next().slideToggle(); }); }); </script> </head> <body> <div id="Sidebar"> <h3>Title 1</h3> <p>Text 1</p> <h3>Title 2</h3> <p>Text 2</p> </div> </body> <!-- ...but roughly down "here" --> </html>
That usage is natural when you’re hedging against AJAX-driven changes in the future. The volatility that you’re concerned with won’t happen until after the page loads, so it’s intuitive to postpone worrying about them until after the document’s ready event.
However, what would happen if you treated your HTML document’s initial load process the same way as any other dynamic modifications?
<html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> <!-- The event handler is wired up "here"; immediately --> $('#Sidebar h3').live('click', function () { $(this).next().slideToggle(); }); </script> </head> <body> <div id="Sidebar"> <h3>Title 1</h3> <!-- At this point, Title 1 is ready for action. --> <p>Text 1</p> <h3>Title 2</h3> <!-- Ditto for Title 2 at this point --> <p>Text 2</p> </div> </body> </html>
Not only does that work just as well as postponing the live() declaration until the document’s ready event, but now the handlers are active during the page loading process. As the browser loads each <h3> element and adds it to the DOM, our click events are immediately ready to be handled.
Benefit: A more responsive UI
To see where the latter approach shines, imagine the page was very large and took several seconds to load, or that a script reference somewhere on the page was timing out. In scenarios like those, jQuery’s document ready event may not fire until considerably later than the targeted elements are visible to your users.
<html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> <!-- The event handler is wired up "here"; immediately --> $('#Sidebar h3').live('click', function () { $(this).next().slideToggle(); }); <!-- This handler isn't active until... --> $(document).ready(function() { $('#Sidebar p').live('click', function() { // Important magic goes here. }); }); </script> </head> <body> <div id="Sidebar"> <h3>Title 1</h3> <p>Text 1</p> </div> <script src="http://twitter.com/fail-whale.js"></script> <!-- ...way down here, *after* the script references times out. --> </body> </html>
Why hold live() back until the document is ready? It doesn’t matter if the selector matches any elements initially; they will immediately become active as they are rendered and appear on the page.
Benefit: Improved performance
A common criticism of using live() for event delegation is that it requires you to perform an initial selection of all of the elements that it targets. Since event delegation doesn’t require any initial setup on each individual element, this pre-selection is a wasteful performance drag when there are dozens or hundreds of elements targeted.
However, if you register your live() handlers before those elements exist on the page, there is no performance penalty whatsoever. The event delegation can be registered very quickly, yet still works exactly the same as if you had waited until the ready event.
<html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> <!-- Fast. Runs before any of the TRs exist. --> $('#MyTable tr').live('click', function () { $(this).toggleClass('highlight'); }); <!-- Slow. Doesn't run until the table is rendered. --> $(document).ready(function() { $('#MyTable tr').live('click', function () { $(this).toggleClass('highlight'); }); }); </script> </head> <body> <table> <!-- Hundreds or thousands of rows here --> </table> </body> </html>
Example: $.ajax()
Another situation where $(document).ready() may be holding you back is when you make an AJAX request immediately as a page is loading. Displaying recent Twitter updates is a common example of that:
<html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> $(document).ready(function() { <!-- $.getJSON() request to retrieve Twitter updates. --> }); </script> </head> <body> <!-- A typically large page here --> </body> <!-- The Twitter request doesn't *begin* until here. --> </html>
Even though the $.getJSON() snippet is located at the beginning of the page, it isn’t executed until the entire page has loaded and the ready event has fired. Why wait until the page is loaded in order to begin the AJAX request?
<html> <head> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> <!-- $.getJSON() request to retrieve Twitter updates. --> <!-- The request begins immediately. --> </script> </head> <body> <!-- A typically large page here --> </body> </html>
This is a nice improvement even when you’re making a request to a local endpoint, but is even more beneficial here because third-party requests circumvent the browser’s per-domain request limit. That third-party request to Twitter runs in parallel with the rest of the page’s normal loading timeline.
Better yet, since the dynamic script element injection used in a JSONP request is asynchronous, there’s no drawback to initiating the request early. Even if Twitter is slow or down (imagine that), the request won’t drag the page down.
Benefit: Performance
To show you a visualization of how the previous two approaches differ, I used my own site as a guinea pig. First, I wrapped a $.getJSON() request to Twitter in $(document).ready() and placed it in the <head> of my site template.
This is how the site loads in that configuration, taken from Firebug’s Net tab:

Now, here’s the same $.getJSON() request, located in the same position in the <head> of the page, but without the $(document).ready() wrapper:

We just pulled a bit of performance right out of thin air. This isn’t simply perceived performance, which is nice enough, but a truly faster overall load time.
Note: You might notice that the ready event came later in the second example and be concerned that it was due to the early $.getJSON() request. It wasn’t. If you look closely, a blocking <script> reference to one of the page’s local scripts took unusually long in the second run, which pushed everything back about 700ms longer than usual.
Conclusion
I think the preceding examples are compelling, but I’m also not suggesting that this is appropriate in every case. Often, it’s best to move every bit of JavaScript to the bottom of your pages (e.g. a public-facing, non-application site like this one). When your scripts are located at the bottom of the page, it doesn’t matter whether you use $(document).ready() or not; everything is effectively running when the document ready event fires anyway.
However, when you’re building the type of script-heavy “application” that behooves your placing script references in the document’s <head>, keeping these ideas in mind can have a tangible impact on the performance of your application.
Similar posts
What do you think?
I appreciate all of your comments, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to another comment, use the threading feature by clicking "Reply to this comment" before submitting your own.
10 Mentions Elsewhere
- Tweets that mention Don’t let jQuery’s $(document).ready() slow you down | Encosia -- Topsy.com
- HashTurmoil :: Speed Up JQuery’s $(document).ready() :: http://excitos.com
- improving Page Download Speeds via Javascript « Bernard's Technocratic Blog
- jQuery: » The Official jQuery Podcast – Episode 32 – Dave Ward
- When not to use jQuery’s document ready handler | A Frontend Engineer's Blog
- Dave Ward | Sachin Handiekar
- jquery resources | 米卡的快乐生活
- Registering jQuery Event Handlers Before the Elements Exist | Ian Dunn
- Don’t let jQuery’s $(document).ready() slow you down « detailfocused
- An interesting point by Dave Ward about jQuery document.ready() .. « happy && coding



Nice post, Dave. Maybe now’s the time to look at using sprites to prevent all those image requests ;o)
Guilty as charged, on that count. I had sprites for most of my images at one point, but haven’t kept up with that as the site design has changed. I really need to get that back under control.
Perhaps you could give the new ASP.NET Sprite control a spin and do a write up on it? My site has so few images, I haven’t bothered :o)
I ran across Sprite Me this week. It helps you combine your sprites and generate the required css.
My question is how do you ensure that JQuery is loaded before running your code? I thought that was the whole point of the document ready event.
Neat link.
We know jQuery is loaded because its script tag is higher up in the page; the page load blocks on the script load. $(document).ready() triggers when the DOM is ready, not jQuery.
I’ve actually started working on a jQuery ready plugin that helps manage must-run-ASAP-code (very much like YUI’s onAvailable and onContentReady events) but I haven’t had time to finish it up yet.. coming soon! :-)
- Cowboy
Beat me to it, :D (both to the implementation and mentioning YUI’s way of doing this).
After reading the $ajax example in your post, I want to mention a case i think we may face:
Suppose the $ajax will start the ajax request and inside ‘onsuccess’ there is some code which manipulates some other html in the page.
I think a problem will happen if the ajax success happened before the page complete loading this html element which the onsuccess need to update.
So i think $ajax without $onready could be tricky in cases like this.
Am i right? or i understood something wrong?
By the way, great article and i didn’t think in this issue before, thanks,
In my experience, the handler is always delayed until the page finishes loading, even if the request finishes before that. It’s my understanding that this behavior is due to the single-threaded execution model that browsers use for page rendering and script execution. Similar to why setTimeout(fn, 0) defers execution until after the page finishes rendering, even if that is much longer than 0 ms.
However, if you want to be extra cautious, you can wrap the success handler in $(document).ready():
$(document).ready() triggers immediately if the page is already loaded, so that code will work no matter when the request comes in.
This thought immediately jumped into my head, as well. Might be worth mentioning it in the article.
Good article, btw!
Would the success handler get called if it was defined in document onready and it was called before the document was ready? Wouldn’t you just get an undefined eror for calling a function that had yet to be defined? If that’s the case it sounds like you would have to be very careful using this method
As long as jQuery has been included on the page before this code, it’s safe.
If the success handler runs before document ready (which I don’t think can happen anyway, due to the single-threaded nature of JavaScript in the browser), then the inner document ready handler there will run when jQuery fires that event.
If the success handler runs after document ready, the inner function will fire immediately. You can wire up a document ready handler at any time during the page’s lifetime; it will just run right away if you do so after document ready has already been raised.
Sorry I misunderstood, I thought you meant wrap an actual function definition in jQuery, not the code that get’s executed inside the function. This makes sense
How a great idea it is!
I have a other question. For the situation that putting js file within head OR js block within head OR js block with in body, is there any other difference besides called sequence and cache ability by browser?
There should be no impact on caching.
It’s definitely best to limit how much JavaScript you place high in the page, because
elements block page rendering until they've finished parsing and executing. That's why you should typically put most of your JavaScript at the very end of the page. However, understanding both that drawback and the benefits covered in my post here, you can balance the two and decide what's best for your particular situation. Sometimes it's definitely worth a slight delay to get an AJAX request in the works as early as possible.you’re right – its an old habit to wrap everything inside the $(document).ready() . so certain events outside doc ready can improve performance – thank you.
Hey Dave interesting stuff!
My question is: what is the trade off in performance for having to add your script tags to the header in order to call the .live() and .ajax() events? Common thought is that forcing the browser to load the library from a suitable CDN or locally is also a performance penalty and, thus, most (including myself) add js lib calls to the bottom of the page/DOM to free up execution of the DOM rendering first… do these techniques described “out weigh” the benefit of loading the jquery library after the DOM and warant taking the *hit* so to speak up front?
Would be curious to see the result of timing before and after implementing this… or I wonder if there is a sweet spot pivot point where if you have lots of .live() or .ajax() event calls this is the better technique? thoughts?
-Kevin
If you’re progressively enhancing a page and have already structured things so that you can include your scripts at the bottom, I definitely would not recommend moving them to the top (see where my script references are on this page, for example). For most public-facing sites that use jQuery to add minor progressive enhancements, that’s best.
The “pivot” (that’s a good term for it) comes when the page depends on JavaScript to function, as is often the case in “application” type sites/pages (think GMail or most Intranet type applications). At that point, you’ll usually be including scripts toward the top of the page and can benefit from the type of optimizations I mentioned above.
If you moved your code block to the bottom of the page, you could benefit from the following (if my understanding is correct):
1. Prevent JS from slowing down the loading of your UI.
2. Ensure that all the DOM elements exist, before the first line of code is read.
3. Because you are confident that all if the DOM elements within body exist, you can make use of the delegate function instead of live. Which in my opinion has a nicer syntax, and allows you to delegate further down the DOM tree.
I think these advantages would add value to the improvements you have already suggested.
Rich
It depends on the type of page/site. On a public-facing page, I’d definitely go with progressive enhancement and scripts at the bottom of the page (view-source on this page and see where the JavaScript is, for example).
In an “application” type scenario, pages often depend so heavily on JavaScript that deferring scripts to the bottom of the page is detrimental. You end up with “flash of unstyled content” issues and momentarily display a half-baked UI to the user, which is worse than making them wait an extra second for scripts to load early. In that sort of situation, where you’re already referencing initialization script at the top of the page, you can take advantage of this opportunity to execute portions of it sooner than $(docuement).ready().
It’s definitely good to understand the benefits of both approaches (script top vs. bottom) and make an informed decision in each individual situation you run into. Neither approach is a panacea.
Great article. I love your point on using the live() method. Why didn’t I think of that :)
I will have to refactor most of my plugins now.
If you guys want more optimization tips, I have testet the jQuery.appent() method for the most optimal use. It has resultet in an interesting test-repport on my blog:
http://rune.gronkjaer.dk/en-US/2010/08/14/jquery-append-speed-test/
Can’t wait to read more of your posts.
/Rune
Dave,
I need a recommendation: I am using ‘datatabes’ plugin and transforming a table into a ‘grid’ (not using json here, just transforming a simple table).
There are times that the page shows the table first and then you see that transformation. I don’t want that to happen – is there a way to prevent that ?
I have $(“”#table”).datatable() in my document ready
The simplest solution to that is to add a style=”display: none;” to the table’s markup, then .show() it after you’ve applied the plugin. That avoids the user seeing a flash of unstyled content, while still displaying it almost immediately after the page loads.
Quick point, this is not a good idea – if a user does not have JS they will never see the table (as they don’t have JS available to set the CSS “display” property to something other than “none” after load).
A better solution is:
This means those without JS will always see the table, those with JS should not get the FOUC.
One last thing, show() and hide() aren’t great for this kind of thing as they cause the area they occupy in the page to be collapsed, which can cause elements to jump all over the page (because of how display:none works). So a further improvement would be to use the CSS property “visibility”. Visibility causes an element to be invisible but still occupy space:
Otherwise can i congratulate you on a fantastic article, Dave. I’m always delighted whenever i see a new article from you in google reader :)
That’s a good point.
Another good way to handle that is to use Modernizr and initially hide the table with a CSS rule like
.js #myGrid { visibility: hidden; }in the page’s CSS (assuming it and Modernizr are included in the head). That way it would only be initially hidden if JavaScript is enabled.Very good point Dave, that’s a much cleaner way of doing it :) still haven’t caught up with all this modernizr jazz amongst all the fanfare it’s getting. Think the cleanliness of this approach will finally spur me to do so!
One thing i’ve never understood is why jQuery doesn’t supply any methods analogous to show/hide for css visibility (unless i’ve somehow missed them). I smell a plugin coming on :-)
Have you tested it by specifying a context? It will probably not work if a context is specified. Without specifying a context, there is a performance hit as it binds to document root.
I would suggest something like jQuery available plugin http://plugins.jquery.com/project/available or looking into YUI’s onAvailable and onContentReady events. Check YUI’s logger output http://developer.yahoo.com/yui/examples/event/event-timing.html
This works well when you are building a website with some dynamic stuff. If you start doing this when you are building a heavy application with lots of client side code you will see a performance hit. JS at the top will halt all other page components from loading, you won’t benefit from parallel loading of images,css, and html. You can see that in your profile graph.
Having the AJAX request in the head is also a bad idea, first you hold one of the browser’s connections for that, instead of using it to load css and images. Second you will hold it again once the callback is triggered.
The best way I found is to be lazy, and leave JS out until you absolutely need it. Use deferred loading of JS, keep it at the bottom. You can shave seconds off the absolute total time but its difficult with a large application (ex. ~1MB of JS) but by staggering your resources, deferring JS and breaking it down into components carefully, you can shave seconds off the perceived load time – which is what really matters.
Thanks for your post, it’s great to see some millisecond–shaving going on :)
I do have a question regarding making Ajax requests, however: If you’re planning on changing a page’s content in response to an Ajax call, what implications would this have? Surely there’s the possibility that jQuery’s ready event won’t have fired by the time that your callback function responds to the Ajax response, so does this mean that you won’t have access to the DOM via jQuery in your Ajax callback function?
In my experience, using this on some of my JavaScript-heavy apps where script references in the <head> make sense, that hasn’t been an issue. I believe it’s a beneficial side-effect of JavaScript’s single-threaded execution model in the browser.
If you want to be extra cautious, wrapping the success handler in $(document).ready() works. If you declare a $(document).ready() handler after the DOM is ready, it will go ahead and execute immediately, so that covers both sides of the event:
In the browsers I’ve tested, that executes at the same time that it would have without the internal $(document).ready() wrapper, but there also should be no drawback to using it there if you prefer the explicit safety.
Yes that’s exactly my question too. It doesn’t work for me. The response from ajax is used to display some content in my page. The ready() is happening before I get a response, even when I have moved ajax at the top.
That’s to be expected. Moving the AJAX request higher in the page will get it started sooner, but it shouldn’t be able to raise its callback before the other JavaScript that’s queued up (like .ready).
The advantage of starting the request sooner is that you can get the response sooner. Instead of starting the request when the page is ready and then getting it sometime after that, you can get your response as soon as immediately after the page is ready.
Hey Dave,
I never knew that about $(document).ready. Awesome, thanks! You probably know this already, but there’s a neat shorthand form of
:
– Ben
It’s true that loading in the head slows you down… the first time. After that, the JS ought to be cached and not slowing you down. It might be best to make your homepage, which “sells” your site, javascript-lite with the scripts at the bottom, but every other page with the javascript at the top. Also, compression and minimizing help your performance.
Once you’ve decided on how to deploy your javascript to the browser, I’ve found the Digg Technique to be incredibly useful. In short, you use bind() to bind the initialization of components on your page to arbirtary tokens. Instead of “ready”, use (for example) “tab-box-ready.” Right under the DIV that contains your tab box, put <script>$(document).trigger(“tab-box-ready”);</script>.
That way, the instant the DOM object associated with behaviors and events is available, you bind the associated javascript to the object. This way, customers never experience odd page behaviors (links that don’t work because the controller isn’t hooked up; hovers that don’t work, etc…); they simply don’t have time.
Yes, it means your page is slightly cluttered with one-liner SCRIPT objects, but I find this an acceptable trade-off to making the page work exactly as the viewer expects.
Methinks this jQuery plugin would make for a cleaner solution:
http://plugins.jquery.com/project/available
Haven’t yet tried it myself, however.
It seems like the “delegate” method was created to address this concern:
http://api.jquery.com/delegate/
Delegate() is definitely better. In addition to avoiding the pre-selection, it can also catch events earlier than live(), since live() events have to bubble all the way up to the root of the DOM before they’re handled, and delegate() can be used after traversal methods whereas live() can’t.
I’ve noticed that a lot of people still like to use live() for its more intuitive syntax though (I’m guilty of that myself sometimes).
Good post Dave. Thanks.
good explained!
Thanks Dave, great post as usual.
It’s a rip-off of this article ? http://alexsexton.com/?p=22
Even the title is almost the same!
Thanks anyway for spreading this information.
That really is quite a coincidence, between the title being similar and the examples covering the same methods, but no I hadn’t seen Alex’s article before.
I imagine 95% of the use cases here would see a greater improvement if they would just optimize out the AJAX request entirely.. In most cases there is no good reason why the server just can’t get that data itself in a more direct fashion.
With that said, it is a valid point that $(document).ready() is abused.
Using AJAX to begin loading ancillary content just after the initial page is received is a good way to speed up getting the core content to the user fast. Especially when dealing with third-party services that may be slow/dead (e.g. Twitter). You could collect it all on the server-side first and send it at once, but it’s definitely going to impact that crucial time-to-first-byte performance on the initial request.
Great posting!
Just a quick hint so others will not try to use .delegate() as idiotic as I did in the beginning:
Trying to execute $(“#myId”).delegate(…) right in the <head> of your document will do nothing at all! The simple reason is that the <body> of your document is not yet loaded yet and there is nothing to bind the delegate handler to. Even $(“body”).delegate(…) will not work for that reason. The only way that you can execute it directly from within the <head> is $(document).delegate(…) !
So basically you will have to put your delegate calls right into the <body> of your HTML, after the HTML nodes you want to bind them too. The part that is accepted “in the future” is the selector param in .delegate(“selector,…) – NOT the HTML node you bind the delegate handler to!
Nice article, thanks, however I have doubts regarding racing condition.
The $(‘p’) will traverse the whole DOM in search for existing , but what if it finishes before the whole page is loaded? Is it going to ‘wait’ or will quit and leave some of the page uninstrumented?
Thanks, Greg.
There’s no race condition. JavaScript execution blocks page rendering and any other JavaScript that comes after. So, if you execute a
$('p'), then nothing else happens until that finishes.As of jQuery 1.7
is deprecated!
You should use
instead: http://api.jquery.com/on/
For this example use:
Great tutorial, really excellent examples (specially the table rows one, incredible performance increase)…
Very nice post! I have begun to notice that when I forgot to add the sytnax line of $(document).ready(); and often caught the mistakes when I debug before finishing the project. I often noticed that kind of pattern of waiting and how it handles the process, exactly what you stated above.
It’s all about timing and the purpose of what you would be trying to accomplish. I only use jquery library line inside
<head>but always used jQuery scripting right before</body>. I also learned that it’s not really necessary to use $(document).ready() if I scripted in the end of html because, the document would be already loaded before the ready() syntax would callback.In some situations, I found that a block of jQuery works only if it’s inside
<head>instead of right before</body>, then I’ll use $(document).ready() when scripting block inside<head>.But yea, I have been tweaking over to $(document).on(). It delivers nicely.
Thank you for this post as a “documentation” about the practice.