Side navigation
#7366 closed enhancement (invalid)
Opened November 01, 2010 08:50AM UTC
Closed December 23, 2010 04:49PM UTC
Last modified March 13, 2012 03:29PM UTC
Asynchronously loading scripts need special care with jQuery.fn.ready
Reported by: | taka.atsushi@gmail.com | Owned by: | |
---|---|---|---|
Priority: | undecided | Milestone: | |
Component: | unfiled | Version: | 1.4.3 |
Keywords: | needsreview | Cc: | |
Blocked by: | Blocking: |
Description
Current implementation of jQuery.fn.ready is like this.
ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // If the DOM is already ready if ( jQuery.isReady ) { // Execute the function immediately fn.call( document, jQuery ); // Otherwise, remember the function for later } else if ( readyList ) { // Add the function to the wait list readyList.push( fn ); }
When a script author writes a script that loads via <scirpt> tag, they can do something like this.
$(function() { foo(); }); var foo = function(){ };
Since $() executes the function asynchronously, the "foo" function will be defined. So there is no problem. But if they start to try <script async> or a custom script loader such as LABjs, and if $() becomes synchronous, this script won't work any more because "foo" will be undefined.
In the case of <script async>, you can't be sure if the script comes before or after DOMContentLoaded. It may be working in the local server where script loads in a moment, but not working somewhere where it takes 5 seconds to load the script.
I think jQuery.fn.ready should execute the function asynchronously even if jQuery.isReady is true, so that scripts are more portable.
Attachments (0)
Change History (4)
Changed November 01, 2010 09:19AM UTC by comment:1
_comment0: | Basically, the complaint here is that because `$.fn.ready` doesn’t unconditionally defer the execution of the function that is passed to it, badly written code with race conditions that incorrectly expect the call will always occur only after the caller has returned will sometimes experience…race conditions. \ \ I’m loathe to call these workarounds since they really are not workarounds but proper coding practice, but the “workarounds” here are: \ \ 1. Use function declarations instead of function literals. \ 2. Use function literals, but define them before calling `$.fn.ready`. \ \ Even if the calls are deferred, you are not guaranteed that a deferred call is going to occur after all asynchronous scripts load, so I am not sure this suggestion will actually solve anything related to the original complaint regarding asynchronously loaded scripts. → 1288603203180186 |
---|---|
keywords: | → needsreview |
milestone: | 1.5 |
Changed November 01, 2010 10:30AM UTC by comment:2
I agree that it's a badly written code, but the I can easily imagine people do it. It's not easy to debug too (in the case of <script async>).
>Use function declarations instead of function literals.
You can't always replace a function declaration with a function literal.
$(function() { foo.bar(); }); var foo = { bar : function() {} };
>Use function literals, but define them before calling $.fn.ready.
Yep, if all scripts were written this way, I wouldn't worry. In reality it's not the case.
>Even if the calls are deferred, you are not guaranteed that a deferred call is going to occur after all asynchronous scripts load
The case I'm talking about does not require ALL scripts to load. Just to wait for parsing of the very script.
Changed December 23, 2010 04:49PM UTC by comment:4
resolution: | → invalid |
---|---|
status: | new → closed |
If we implemented this we'd be making a significant breaking change, because this has been in the .ready()
documentation for some time:
If .ready() is called after the DOM has been initialized, the new handler passed in will be executed immediately.
So I'm going to close this ticket.
Basically, the complaint here is that because
$.fn.ready
doesn’t unconditionally defer the execution of the function that is passed to it, badly written code with race conditions that incorrectly expect the call will always occur only after the caller has returned will sometimes experience…race conditions.I’m loathe to call these workarounds since they really are not workarounds but proper coding practice, but the “workarounds” here are:
1. Use function declarations instead of function literals.
2. Use function literals, but define them before calling
$.fn.ready
.Even if the calls are deferred, you are not guaranteed that a deferred call is going to occur after all asynchronous scripts load (only that they will occur after the engine reaches the top of the call stack), so I am not sure this suggestion will actually solve anything related to the original complaint regarding asynchronously loaded scripts.