TL;DR - async
execute at any time and in any order, defer
and "normal" execute in the order they are declared (but all defer
after all the "normal").
Find an accurate specification of the behavior of async
and defer
is complicated, since they have influence in several stages of processing the browser. According to the specification of HTML5:
Note: The exact processing details for these attributes are, primarily for historical reasons, somewhat non-trivial, involving a number of aspects of HTML. The implementation requirements are therefore by necessity spread across the specification. The low algorithms (in this section) describe the core of this processing, but these algorithms reference and are referenced by the rules of Parsing for the tags script
of beginning and end in HTML, in foreign content, and in XML, the rules for the method document.write()
, the handling of the scripting, etc..
Some of the question points are responsive by specification, however:
B can perform before A, if your charge is faster? Or the defer
imposes an order on other scripts also with defer
?
No, the order is respected. According to this same specification, there is a list of scripts to be executed when the document Parsing, and each script with defer
should be included at the end of that list:
To prepare the script, the user agent must Act as Follows:
Then, the first of the following options that describes the Situation must be Followed:
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.
That way, if a browser acts in accordance with that specification (see tests below) and executes the scripts in the order they were inserted into that list (i.e. the order in which it appears in the source code) so if I load, say, the jQuery of a CDN, the bootstrap of another, and my own server code, all with defer
, they must execute in that same order, so that dependence on one another must be satisfied.
<script src="//code.jquery.com/jquery-2.1.4.min.js" defer></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" defer></script>
<script src="/js/meucodigo.min.js" defer></script>
But attention: If the browser does not give proper support to HTML5, scripts defer
can yes perform out of order! According to html 4 specification, the defer
is just a "hint" to browser that the script will not produce any content to the document (e.g.: via document.write
) and so he can continue to do the parse and rendering. Nothing else is specified, so it is safe to assume that the execution order may vary from implementation to implementation.
If D is loaded while E is loading (but not running), it will execute before E or not?
I think yes. The specification applicable to items with async
(same item 15 above) says the following:
The task that the task source networking Places on the task Queue Once the fetching Algorithm has completed must execute the script block and then remove the element from the set of scripts that will execute as soon as possible.
In contrast, the elements without async
have a different behaviour:
The element is the pending Parsing-blocking script of the Document of the parser that created the element. (There can only be one such script per Document at a time.)
The task that the task source networking Places on the task Queue Once the fetching Algorithm has completed must set the element’s "ready to be parser-executed" flag. The parser will Handle executing the script.
That is, when the browser finds one or more scripts with async
(ex.: C and D), he places them in the task queue and moves on. When he finds a without async
(nor defer
) it also puts you in the job queue, but marks it as "blocker Parsing". I don’t quite understand what that means (because the process of Parsing in general it is described in another document - I’m not sure which), but in practice it should serve to interrupt the rendering (but not necessarily the load) until the script has just run.
However, it is unclear whether the presence of a "blocker script Parsing" is or is not hindering the task of completing scripts async
("execute the script block") is executed in that state. When in doubt, I will adopt a conservative stance and assume that "no" (i.e. I will work with the hypothesis that after the load of E begin - but before its execution - C and D may perform).
The tests below seem to corroborate this my interpretation.
C and D can run after A and B? (...) or it is necessary that all async scripts run before any Defer script runs?
Yes, they can execute at any time. I couldn’t find anything in the specification that would prohibit scripts in the list of "scripts to be executed as soon as possible" from running after scripts in the list of "scripts to be executed when the document finishes the Parsing". In fact, a simple test in Chrome (without webserver, in the file system itself) came to order "C,E,F,A,B,D" in one of the tests, and "E,F,A,B,C,D" in others.
Testing
To test the actual behavior of browsers, I made a small change in the SimpleHTTPServer
python:
import SimpleHTTPServer, SocketServer, sys, time
from SimpleHTTPServer import SimpleHTTPRequestHandler
class MeuHTTPServer(SimpleHTTPRequestHandler):
def do_GET(*args, **kwargs):
time.sleep(int(sys.argv[2]))
return SimpleHTTPRequestHandler.do_GET(*args, **kwargs)
SocketServer.TCPServer(("", int(sys.argv[1])), MeuHTTPServer).serve_forever()
And I opened the program 7 times, one to serve each file (the 6 scripts and the html itself). "Large" scripts (A,C,E) wait 5 seconds before returning, "small" scripts (B,D,F), 1 second. The html used was:
<html>
<body>
<script src="http://localhost:8001/a.js" defer></script>
<script src="http://localhost:8002/b.js" defer></script>
<script src="http://localhost:8003/c.js" async></script>
<script src="http://localhost:8004/d.js" async></script>
<script src="http://localhost:8005/e.js"></script>
<script src="http://localhost:8006/f.js"></script>
</body>
</html>
And each script just makes one console.log
to "identify themselves". The results (in Windows 7) were:
- Firefox: "D,E,F,A,B,C", showing all the points cited (including the request
GET
of all the scripts were made before of d
run - confirming a script async
can perform while a "normal" is charging). In another test, "D,C,E,F,A,B" (also consistent with the rest of the answer). After that, "C,D,E,F,A,B" after the scripts enter the cache.
- Chrome: "D,C,E,F,A,B" in 2 tests, "E,F,A,B,C,D" after the scripts entered the cache (I noticed a trend of the scripts
async
be executed lastly - even after the defer
- unlike Firefox, which tends to run them in order).
- Internet Explorer 11: "D,E,C,F,A,B" (demonstrating that a script
async
in fact can run between two "normal") the first time, "D,C,E,F,A,B" in the following (apparently the IE does not put resources from the localhost
cached).
- Opera and Safari: "D,C,E,F,A,B" in 1 test, "E,F,A,B,C,D" in the others (same as Chrome).
My conclusion is that the interpretation I gave to the specification is correct, and the main ones browsers comply with that specification.
possible duplicate of About the boolean attribute Defer and async vs optimization
– SneepS NinjA
da uma lida aqui http://answall.com/a/46475/12032
– SneepS NinjA
In the response of re22 says he has no way of knowing the execution of defers. But here I understand it’s in order of occurrence.
– Franchesco
@Sneepsninja I had already read this answer, but it did not clarify all my doubts. Perhaps some of your external references answered, but I missed a more direct answer with regard to order, hence the question. Also, I read some conflicting references (ex.: this site says "If the script relies upon or is relied upon by Another script then use Defer", but this contradicts the linked answer, which says "there is no way of knowing in which order they will be executed"; which is right? Etc.).
– mgibsonbr
As far as I have read, my English is well +- so I may be mistaken, Defer "was" to ensure the order of the post-load scripts of the page but in practice it does not guarantee http://stackoverflow.com/questions/5250412/how-exactly-does-script-defer-work
– SneepS NinjA
In practice it is recommended to compress everything into a single script, both to decrease latency and to avoid these "issues of order". Then you can use Defer and async at the same time.
– epx
@epx Sure, but even though this "one size fits all" solution covers 95% of cases, it is far from perfect. As I have already commented in that other answer, where you put the script has an impact on the user experience (e.g., waiting longer and seeing "beautiful" content, or seeing "raw" content faster and unexpectedly seeing it change in response to the script, if only CSS is not enough), and unifying complicates the use of Cdns. Knowing more about the subject gives us more tools to get closer to the ideal outcome for each particular case.
– mgibsonbr
@Sneepsninja Since no one answered, I did some research, some tests, and gave a self answer. In fact, in HTML 4 the order of
defer
was not specified, and browsers could execute them in the order they wanted (as the answer you linked - 2011 - also states). HTML5 imposes yes an order, and the browsers modern apparently respect it.– mgibsonbr