Browse files

Allow plugins to delay the exeuction of the ready event. Delay the re…

…ady event by calling: jQuery.readyWait++ and force the event to fire by doing: jQuery.ready(true). Fixes #6781.
  • Loading branch information...
1 parent 5b92cdd commit 747ba7defd82bffa6c7ccb69e53b834cbfddb62c @jeresig jeresig committed Sep 20, 2010
Showing with 16 additions and 2 deletions.
  1. +16 −2 src/core.js
@@ -360,11 +360,20 @@ jQuery.extend({
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
// Handle when the DOM is ready
- ready: function() {
+ ready: function( wait ) {
+ // A third-party is pushing the ready event forwards
+ if ( wait === true ) {
+ jQuery.readyWait--;
+ }
// Make sure that the DOM is not already loaded
- if ( !jQuery.isReady ) {
+ if ( !jQuery.readyWait && !jQuery.isReady ) {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( jQuery.ready, 13 );
@@ -373,6 +382,11 @@ jQuery.extend({
// Remember that the DOM is ready
jQuery.isReady = true;
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
// If there are functions bound, to execute
if ( readyList ) {
// Execute all of them

5 comments on commit 747ba7d


jrburke replied Sep 23, 2010

Thank you for addressing the ticket! This approach covers most cases, but I believe it may fire the ready callbacks before all scripts are loaded in the following case:

  • A script loader is used to load jQuery via async script elements dynamically added to the DOM. The script loader knows to increment jQuery.readyWait after jQuery loads but needs to do that work in the script onload event for the script element that loads jQuery.
  • Page is loaded without jQuery and DOMContentedLoaded fires. Later the page loads jQuery, or jQuery is loaded via an async script tag, but DOMContentLoaded fires before the jQuery script is executed.
  • At this point the script containing jQuery is executed. The script that contains jQuery has been optimized to include other jQuery plugins, that register ready callbacks with jQuery. There are other scripts loading on the page via other script tags, so the script loader does not consider that the page is really "ready" yet.
  • jQuery executes, and will see document.readyState === "complete" and since the script is still executing, the script loader will not have had a chance to increment readyWait, so the ready callbacks will fire, even though there are other scripts being loaded.

One solution may be to use a setTimeout for the jQuery.ready() call that is done around line 431 in core.js related to the document.readyState === "complete" that is long enough that it allows the script onload event handler to fire before the setTimeout callback. The script loader would use the script onload event to increment jQuery.readyWait. This is complicated a bit by IE 6-8 that can evaluate a few scripts in a row before the script onload callbacks fire, so I am not sure if the setTimeout could get in the event queue before the script onload, but I expect that chances of that happening will be incredibly small.

Another option is what was illustrated in the attachment to #6781, where instead of using a readyWait property on the jQuery object, use a property on the DOM that holds the wait count. This approach allows the script loader to increment that value before jQuery is loaded. jQuery could then watch for changes to that property to know when to trigger jQuery.ready itself. However, if the code to set up the watch seemed like too much overhead, just coordinating on the DOM property name and asking script loaders to call jQuery.ready directly would still work. The down side is a "global" on the document, but I think this is one case where it makes sense, and it allows other toolkits to leverage the same feature when working with script loaders that only consider the page "ready" when all outstanding scripts have been loaded.


jeresig replied Sep 23, 2010

I went with the first solution, I think it's preferred - I'm very much against having some sort of global (even if it's on the document). I landed it in e270d80. Thanks for the detailed description of this issue, though!


jrburke replied Sep 23, 2010

Awesome, thanks!


dmethvin replied Sep 28, 2010

I just noticed which was pushed to 1.5; it proposes to extend .ready() for frames. If that is landed in 1.5 we'll need to make the readyWait counter specific to a document.


jeresig replied Sep 28, 2010

I had forgotten about that patch - although I don't think that it'll affect what's happening here. The readyWait property is very specific to just delaying the single global ready event - ready for individual frames is fine and doesn't need this functionality (jQuery is already loaded at this point and can delay execution of the even in any way they choose).

Please sign in to comment.