Skip to content

Script defer is wrong #5669

@mathsite

Description

@mathsite

In Chrome, FX and IE >=10 <script defer> should cause scripts to be background loaded, but then executed in order before DOMContentLoaded fires.

However, when lots of scripts are loaded with defer applied the jQuery event fires before all the scripts have run.

You can test this with:

file 1.js:

window.test = "fail init";
// test result when jQuery ready fires
$(function() {$('#resultJQ').html("jQuery result: " + window.test);});

// test result when document is ready
document.addEventListener("DOMContentLoaded", function() {$('#resultDOM').html("DOM result: " + window.test);});
file 2-9.js:

window.test = "fail " + n;
file 10.js:

window.test = "pass"
page.html:

<script type="text/javascript" src="jquery.js" defer></script> <script type="text/javascript" src="1.js" defer></script> ... <script type="text/javascript" src="n.js" defer></script> ... <script type="text/javascript" src="10.js" defer></script>
waiting...
waiting...
Both tests pass when files load fast enough, but sufficient delays (>50ms each) in the *.js files cause the jQuery test to fail in latest Chrome and FX. It doesn't fail consistently, but the jQuery ready always fires before the document one.

Here is a jsBin that reproduces it on first load, although this might depend on your network and subsequent loads won't show the bug. Try throttling your connection and CTRL+F5 if it doesn't happen on first load.

This bug is extant in the latest 2.x and 3.x but doesn't seem to occur in 1.x

This appears to be due to this check:

// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE <=9 - 10 only
// Older IE sometimes signals "interactive" too soon
if ( document.readyState === "complete" ||
( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {

// Handle it asynchronously to allow scripts the opportunity to delay ready
window.setTimeout( jQuery.ready );

}
When debugging it appears that document.readyState === 'interactive' and !document.documentElement.doScroll is true, so jQuery.ready fires with the minimum delay (4ms). Breaking on window.setTimeout halts execution while some of the numbered js files are still pending in the Network tab.

I don't know whether this is a recent change in behavior, but Chrome and Firefox appear to report document.readyState === 'interactive' as soon as the body is present, but before deferred scripts are evaluated.

This isn't a problem in IE < 10 as it doesn't support defer (it sort of does, but fires scripts out of order and so would fail this test anyway).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions