Skip to main content

Bug Tracker

Side navigation

#12044 closed feature (wontfix)

Opened July 09, 2012 02:10PM UTC

Closed January 04, 2013 10:15PM UTC

ready callback should always be called asynchronously

Reported by: tj@crowdersoftware.com Owned by:
Priority: low Milestone: 1.9
Component: deferred Version: 1.7.2
Keywords: Cc:
Blocked by: Blocking:
Description

The documentation of ready says:

If .ready() is called after the DOM has been initialized, the new handler passed in will be executed immediately.

...and by "immediately" it means "synchronously."

Which is a problem: The handler should always be called asynchronously, even if the DOM is ready. This prevents ready from having chaotic behavior. For instance, it's impossible to look at this code and determine the order in which "B" and "C" are logged:

console.log("A");
jQuery(function($) {
  console.log(B");
});
console.log("C");

In the normal case (DOM not yet ready when ready is called), we'll get

A
C
B

...but if the DOM is already ready, we'll get

A
B
C

This allows bugs to slip in, where there is an undetected dependency on the order of B and C and a script is only tested in one situation or the other.

Somewhat gratuitous example showing the three situations in which ready might be called (1. DOM not ready; 2. During another ready handler; 3. DOM ready), and how they behave: http://jsbin.com/ezowij The output is:

Outer : ACB
Inner : ACB
Delayed : ABC

Note the third is different. My belief is that if a callback ''may'' be asynchronous, it should always be asynchronous, and so I'd rather see consistency.

Attachments (0)
Change History (11)

Changed July 09, 2012 02:12PM UTC by scottgonzalez comment:1

If/when #10467 is resolved, this will automatically happen :-)

Changed July 10, 2012 12:39AM UTC by dmethvin comment:2

component: unfileddeferred
milestone: None1.9
priority: undecidedlow
status: newopen

Changed September 09, 2012 01:10AM UTC by dmethvin comment:3

type: enhancementfeature

Bulk change from enhancement to feature.

Changed December 03, 2012 06:07PM UTC by jaubourg comment:4

blockedby: → 10467

Changed December 09, 2012 05:30PM UTC by dmethvin comment:5

Leaving this open since it can be solved with setTimeout. Is it worth adding that though?

Changed December 09, 2012 06:28PM UTC by T.J. Crowder <tj@crowdersoftware.com> comment:6

Replying to [comment:5 dmethvin]:

Is it worth adding that though?

I'd say so, for the consistent behavior.

Changed December 09, 2012 06:39PM UTC by dmethvin comment:7

The downside is that it probably adds at least 16ms of delay to document ready for everyone, since APIs like setImmediate() aren't available.

Changed December 10, 2012 07:59AM UTC by T.J. Crowder <tj@crowdersoftware.com> comment:8

Replying to [comment:7 dmethvin]:

The downside is that it probably adds at least 16ms of delay to document ready for everyone, since APIs like setImmediate() aren't available.

If you're optimizing to that level, you don't use ready anyway, although in my tests setTimeout only routinely adds 15ms in IE; on Chrome I get 7ms on average, Opera about 7.5ms, and Firefox less than 4ms.

I would also advocate only using setTimeout when the DOM is already ready, but a quick look at the latest suggests ready has been promise-ified which might make that difficult.

Changed December 11, 2012 08:32PM UTC by pbramos comment:9

I've started looking at this today and will take ownership of it if no one else has made any progress.

Changed December 12, 2012 01:41AM UTC by jaubourg comment:10

It's a -1 for me. The consistency argument seems rather specious to me.

Changed January 04, 2013 10:15PM UTC by dmethvin comment:11

resolution: → wontfix
status: openclosed

This really comes down to the same problem we've argued ad nauseum with promises and their sync/async resolution. For better or worse, we have quite a bit of code that depends on the current behavior and we've documented that the callback is called "immediately" when the DOM is ready.

The good news is that someone who needs the async resolution is free to guarantee that with a setTimeout() inside their own code. If were were to "fix" this, it wouldn't be possible to get the synchronous behavior back.