Bug Tracker

Opened 7 years ago

Closed 7 years ago

#12044 closed feature (wontfix)

ready callback should always be called asynchronously

Reported by: tj@… Owned by:
Priority: low Milestone: 1.9
Component: deferred Version: 1.7.2
Keywords: Cc:
Blocked by: #10467 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 `ready`: ACB
Inner `ready`: ACB
Delayed `ready`: 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.

Change History (11)

comment:1 Changed 7 years ago by scottgonzalez

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

comment:2 Changed 7 years ago by dmethvin

Component: unfileddeferred
Milestone: None1.9
Priority: undecidedlow
Status: newopen

comment:3 Changed 7 years ago by dmethvin

Type: enhancementfeature

Bulk change from enhancement to feature.

comment:4 Changed 7 years ago by jaubourg

Blocked by: 10467 added

comment:5 Changed 7 years ago by dmethvin

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

comment:6 in reply to:  5 Changed 7 years ago by T.J. Crowder <tj@…>

Replying to dmethvin:

Is it worth adding that though?

I'd say so, for the consistent behavior.

comment:7 Changed 7 years ago by 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.

comment:8 in reply to:  7 Changed 7 years ago by T.J. Crowder <tj@…>

Replying to 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.

comment:9 Changed 7 years ago by pbramos

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

comment:10 Changed 7 years ago by jaubourg

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

comment:11 Changed 7 years ago by dmethvin

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.

Note: See TracTickets for help on using tickets.