Ticket #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: | ||
| Blocking: | Blocked by: | #10467 |
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
comment:2 Changed 11 months ago by dmethvin
- Priority changed from undecided to low
- Status changed from new to open
- Component changed from unfiled to deferred
- Milestone changed from None to 1.9
comment:3 Changed 9 months ago by dmethvin
- Type changed from enhancement to feature
Bulk change from enhancement to feature.
comment:5 follow-up: ↓ 6 Changed 6 months ago by dmethvin
Leaving this open since it can be solved with setTimeout. Is it worth adding that though?
comment:7 follow-up: ↓ 8 Changed 6 months 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 5 months 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 5 months 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 5 months ago by jaubourg
It's a -1 for me. The consistency argument seems rather specious to me.
comment:11 Changed 5 months ago by dmethvin
- Status changed from open to closed
- Resolution set to wontfix
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.
Please follow the bug reporting guidlines and use jsFiddle when providing test cases and demonstrations instead of pasting the code in the ticket.

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