question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

<script defer> fires after $(function) in Chrome and FX

See original GitHub issue

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:

<!DOCTYPE html>
<html>
<head>
    <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>
</head>
<body>
    <div id="resultJQ">waiting...</div>
    <div id="resultDOM">waiting...</div>
<body>
</html>

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).

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:9
  • Comments:26 (8 by maintainers)

github_iconTop GitHub Comments

4reactions
gkatsanoscommented, May 22, 2017

TL/DR is “don’t load jQuery with defer” ? I struggled hours with a bug before I ended up here 😕 (and yes removing defer solves it)

1reaction
dmethvincommented, Jul 21, 2019

@shmdhussain The ticket has all that information. Open, assigned to timmywil, scheduled for 4.0 since it is a breaking change for people depending on the current behavior.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How exactly does <script defer="defer"> work? - Stack Overflow
It starts fetching the script file while parsing the HTML side-by-side. But stops the HTML parsing when the script is completely fetched, after...
Read more >
the script defer attribute - the Web developer blog
The defer attribute is boolean attribute that indicates how the script should be executed. If the defer attribute is present, then the script...
Read more >
4. Loading Scripts Without Blocking - Even Faster Web Sites ...
Script Defer shouldn't be used because it forces scripts to be loaded in order, whereas the page loads faster if scripts are executed...
Read more >
Scripts: async, defer - The Modern JavaScript Tutorial
The defer attribute tells the browser not to wait for the script. Instead, the browser will continue to process the HTML, build DOM....
Read more >
Chapter 14 Handling Events - Eloquent JavaScript
Every DOM element has its own addEventListener method, which allows you to ... Instead, there exists another event, "keypress" , which fires right...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found