How exactly does <script defer="defer"> work?
Asked Answered
I

11

226

I have a few <script> elements, and the code in some of them depend on code in other <script> elements. I saw the defer attribute can come in handy here as it allows code blocks to be postponed in execution.

To test it I executed this on Chrome: http://jsfiddle.net/xXZMN/.

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

However, it alerts 2 - 1 - 3. Why doesn't it alert 1 - 2 - 3?

Imbibe answered 9/3, 2011 at 18:29 Comment(7)
Maybe check out this article. And, as always, IE has their own take on what something means and decided to load the script first but delay execution until the body is loaded (typically).Happygolucky
Thanks, however the test page has a different result on Chrome: websiteoptimization.com/speed/tweak/defer/test. The screenshot shows how I would expect it, whilst Chrome just seems to execute the deferred first.Imbibe
I think you'll find the IE's definition of defer, matches the W3C's intent for defer in the DOM Level 1 spec.Mariselamarish
As Alohci already pointed out in his answer, according to the HTML Standard defer is only valid when specifying src. This might be a reason why your example did not work as expected in most browsers.Hahnke
@Hahnke True story! Try jsfiddle.net/xXZMN/50 Tested in Firefox24Cockswain
Found this diagram very helpful to understand defer and differences between async and defer: growingwiththeweb.com/2014/02/async-vs-defer-attributes.htmlPyrite
#41395483Aphonia
M
52

UPDATED: 2/19/2016

Consider this answer outdated. Refer to other answers on this post for information relevant to newer browser version.


Basically, defer tells the browser to wait "until it's ready" before executing the javascript in that script block. Usually this is after the DOM has finished loading and document.readyState == 4

The defer attribute is specific to internet explorer. In Internet Explorer 8, on Windows 7 the result I am seeing in your JS Fiddle test page is, 1 - 2 - 3.

The results may vary from browser to browser.

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

Contrary to popular belief IE follows standards more often than people let on, in actuality the "defer" attribute is defined in the DOM Level 1 spec http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html

The W3C's definition of defer: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer:

"When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering."

Mariselamarish answered 9/3, 2011 at 19:9 Comment(5)
@MarkAtRamp51 - If your answer is outdated, you should edit it instead of complaining about downvotes in comments on other answers. Downvotes are for answers that are "not useful."Anglaangle
@ChristianConkle I appreciate the etiquette lesson, however the other answers here are up to date. I was addressing the fact that the wrong answer wasn't selected at the time the question was asked. Perhaps you should police the folks spreading false assessments about the community improperly selecting answers, instead of folks trying to remind people that things change over time, and context is important. I don't see value in removing my answer as historical information is valuable also.Mariselamarish
" I don't see value in removing my answer as historical information is valuable also" In that case, how about adding a note in the beginning pointing out that it only applies to pre-HTML5, and then linking to the "correct" (up-to-date) answer? That should save you a lot of trouble (speaking as a guy who also had a "wrong" answer accepted once, and was "peer-pressured" to eventually change it).Alainaalaine
@Leo should it not be flagged then? By searching "html5 defer script" this is the third result in google. This answer then is providing a lot of users with outdated and, incorrect definition. (The current definition: "Indicates that the user agent can defer processing of the script. See the defer attribute definition in HTML 4.0.").Canberra
@MarkAtRamp51I think you should update your answer. Anyone who finds this question and so your answer will not recognise its historical information. It will look to them like it's the answer which is correct today. That's how the internet works. So you should edit your answer, note that it was correct once upon a time, and refer to the correct answer.Kimbra
G
173

A few snippets from the HTML5 spec: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

The defer and async attributes must not be specified if the src attribute is not present.


There are three possible modes that can be selected using these attributes [async and defer]. If the async attribute is present, then the script will be executed asynchronously, as soon as it is available. If the async attribute is not present but the defer attribute is present, then the script is executed when the page has finished parsing. If neither attribute is present, then the script is fetched and executed immediately, before the user agent continues parsing the page.


The exact processing details for these attributes are, for mostly historical reasons, somewhat non-trivial, involving a number of aspects of HTML. The implementation requirements are therefore by necessity scattered throughout the specification. The algorithms below (in this section) describe the core of this processing, but these algorithms reference and are referenced by the parsing rules for script start and end tags in HTML, in foreign content, and in XML, the rules for the document.write() method, the handling of scripting, etc.


If the element has a src attribute, and the element has a defer attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute:

The element must be added to the end of the list of scripts that will execute when the document has finished parsing associated with the Document of the parser that created the element.

Ginnifer answered 9/3, 2011 at 19:36 Comment(4)
Maybe, my response here will stop people from down voting my answer, due to your not helpful comment. The accepted answer isn't wrong, the answer is different, because in early 2011 the HTML5 spec was less relevant to the mainstream webbrowsers than it is currently. This answer might be better going forward, but the accepted answer isn't WRONG by any standard.Mariselamarish
While it's useful to know what the spec says, it turns out that some browsers like IE<9 implement defer badly. If you use defer, you can't rely on the script files being executed in order in some browsers.Brownley
@Brownley Not just IE, it seems that the execution order is not guaranteed in Firefox either.Churchwoman
The first quote is not valid anymore right? Now i can read this: "The attribute must not be specified if the src attribute is not present, or if the script is not a classic script.". And a classic script is one without src="" too.Inefficacious
C
162

The real answer is: Because you cannot trust defer.

In concept, defer and async differ as follows:

async allows the script to be downloaded in the background without blocking. Then, the moment it finishes downloading, rendering is blocked and that script executes. Render resumes when the script has executed.

defer does the same thing, except claims to guarantee that scripts execute in the order they were specified on the page, and that they will be executed after the document has finished parsing. So, some scripts may finish downloading then sit and wait for scripts that downloaded later but appeared before them.

Unfortunately, due to what is really a standards cat fight, defer's definition varies spec to spec, and even in the most recent specs doesn't offer a useful guarantee. As answers here and this issue demonstrate, browsers implement defer differently:

  • In certain situations some browsers have a bug that causes defer scripts to run out of order.
  • Some browsers delay the DOMContentLoaded event until after the defer scripts have loaded, and some don't.
  • Some browsers obey defer on <script> elements with inline code and without a src attribute, and some ignore it.

Fortunately the spec does at least specify that async overrides defer. So you can treat all scripts as async and get a wide swath of browser support like so:

<script defer async src="..."></script>

98% of browsers in use worldwide and 99% in the US will avoid blocking with this approach.

(If you need to wait until the document has finished parsing, listen to the event DOMContentLoaded event or use jQuery's handy .ready() function. You'd want to do this anyway to fall back gracefully on browsers that don't implement defer at all.)

Clemmy answered 24/5, 2012 at 4:37 Comment(5)
I believe this is incorrect. The benefit of defer is that it does not execute until parsing of the page is complete. This page has a good visual to explain the difference between async and defer: peter.sh/experiments/…Maggiemaggio
@Maggiemaggio In concept you are correct; in practice this does not turn out to be true. Because it's not implemented consistently, the sequence guarantee is not universal, and so, not a guarantee. When implementing something you care about execution. The intent of the design is cute, but, not particularly helpful.Clemmy
Just wanted to point out that Opera has supported the defer attribute since version 15, which was released on June 2nd, 2013.Jugal
why to use defer async together? should not we use either async or defer? Please elaborate :)Cauvery
@VikasBansal For older browsers that don't support async - namely older IE.Clemmy
M
52

UPDATED: 2/19/2016

Consider this answer outdated. Refer to other answers on this post for information relevant to newer browser version.


Basically, defer tells the browser to wait "until it's ready" before executing the javascript in that script block. Usually this is after the DOM has finished loading and document.readyState == 4

The defer attribute is specific to internet explorer. In Internet Explorer 8, on Windows 7 the result I am seeing in your JS Fiddle test page is, 1 - 2 - 3.

The results may vary from browser to browser.

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

Contrary to popular belief IE follows standards more often than people let on, in actuality the "defer" attribute is defined in the DOM Level 1 spec http://www.w3.org/TR/REC-DOM-Level-1/level-one-html.html

The W3C's definition of defer: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer:

"When set, this boolean attribute provides a hint to the user agent that the script is not going to generate any document content (e.g., no "document.write" in javascript) and thus, the user agent can continue parsing and rendering."

Mariselamarish answered 9/3, 2011 at 19:9 Comment(5)
@MarkAtRamp51 - If your answer is outdated, you should edit it instead of complaining about downvotes in comments on other answers. Downvotes are for answers that are "not useful."Anglaangle
@ChristianConkle I appreciate the etiquette lesson, however the other answers here are up to date. I was addressing the fact that the wrong answer wasn't selected at the time the question was asked. Perhaps you should police the folks spreading false assessments about the community improperly selecting answers, instead of folks trying to remind people that things change over time, and context is important. I don't see value in removing my answer as historical information is valuable also.Mariselamarish
" I don't see value in removing my answer as historical information is valuable also" In that case, how about adding a note in the beginning pointing out that it only applies to pre-HTML5, and then linking to the "correct" (up-to-date) answer? That should save you a lot of trouble (speaking as a guy who also had a "wrong" answer accepted once, and was "peer-pressured" to eventually change it).Alainaalaine
@Leo should it not be flagged then? By searching "html5 defer script" this is the third result in google. This answer then is providing a lot of users with outdated and, incorrect definition. (The current definition: "Indicates that the user agent can defer processing of the script. See the defer attribute definition in HTML 4.0.").Canberra
@MarkAtRamp51I think you should update your answer. Anyone who finds this question and so your answer will not recognise its historical information. It will look to them like it's the answer which is correct today. That's how the internet works. So you should edit your answer, note that it was correct once upon a time, and refer to the correct answer.Kimbra
A
15

defer can only be used in <script> tag for external script inclusion. Hence it is advised to be used in the <script>-tags in the <head>-section.

Aun answered 16/10, 2013 at 6:43 Comment(0)
T
10

As defer attribute works only with scripts tag with src. Found a way to mimic defer for inline scripts. Use DOMContentLoaded event.

<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
    // Your inline scripts which uses methods from external-scripts.
});
</script>

This is because, DOMContentLoaded event fires after defer attributed scripts are completely loaded.

Twopiece answered 5/9, 2015 at 13:32 Comment(0)
P
8

The defer attribute is only for external scripts (should only be used if the src attribute is present).

Pensioner answered 8/5, 2013 at 6:29 Comment(0)
B
6

Have a look at this excellent article Deep dive into the murky waters of script loading by the Google developer Jake Archibald written in 2013.

Quoting the relevant section from that article:

Defer

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec says: Download together, execute in order just before DOMContentLoaded. Ignore “defer” on scripts without “src”.

IE < 10 says: I might execute 2.js halfway through the execution of 1.js. Isn’t that fun??

The browsers in red say: I have no idea what this “defer” thing is, I’m going to load the scripts as if it weren’t there.

Other browsers say: Ok, but I might not ignore “defer” on scripts without “src”.

(I'll add that early versions of Firefox trigger DOMContentLoaded before the defer scripts finish running, according to this comment.)

Modern browsers seem to support async properly, but you need to be OK with scripts running out of order and possibly before DOMContentLoaded.

Brownley answered 20/1, 2016 at 13:1 Comment(0)
C
6

<script defer> -
As soon as the browser interacts with the script tag with defer

  1. It starts fetching the script file while also parsing the HTML side-by-side.
  2. In this case, the script is only executed once the HTML parsing is completed.

<script async>
As soon as the browser interacts a script tag with async

  1. It starts fetching the script file while parsing the HTML side-by-side.
  2. But stops the HTML parsing when the script is completely fetched, after which it starts executing the script, post which the HTML parsing continues.

<script>
As soon as the browser interacts with a script tag

  1. It stops the parsing of HTML, fetches the script file,
  2. In this case, executes the script, and then continues the parsing of HTML.
Combine answered 25/7, 2021 at 2:57 Comment(0)
W
4

Should be also noted that there might be problems in IE<=9 when using script defer in certain situations. More on this: https://github.com/h5bp/lazyweb-requests/issues/42

Woolf answered 10/10, 2013 at 15:32 Comment(0)
U
1

This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed. Since this feature hasn't yet been implemented by all other major browsers, authors should not assume that the script’s execution will actually be deferred. Never call document.write() from a defer script (since Gecko 1.9.2, this will blow away the document). The defer attribute shouldn't be used on scripts that don't have the src attribute. Since Gecko 1.9.2, the defer attribute is ignored on scripts that don't have the src attribute. However, in Gecko 1.9.1 even inline scripts are deferred if the defer attribute is set.

defer works with chrome , firefox , ie > 7 and Safari

ref: https://developer.mozilla.org/en-US/docs/HTML/Element/script

Update answered 18/2, 2013 at 6:11 Comment(0)
S
0

The defer attribute is a boolean attribute.

When present, it specifies that the script is executed when the page has finished parsing.

Note: The defer attribute is only for external scripts (should only be used if the src attribute is present).

Note: There are several ways an external script can be executed:

If async is present: The script is executed asynchronously with the rest of the page (the script will be executed while the page continues the parsing) If async is not present and defer is present: The script is executed when the page has finished parsing If neither async or defer is present: The script is fetched and executed immediately, before the browser continues parsing the page

Schreibe answered 1/7, 2016 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.