如果您没有动态加载脚本或将它们标记为延迟或异步,则脚本将按照页面中遇到的顺序加载。不管它是一个外部脚本还是一个内联脚本——它们都是按照在页面中遇到的顺序执行的。外部脚本之后的内联脚本将被保留,直到它们之前的所有外部脚本都加载并运行。
异步脚本(不管它们是如何被指定为异步的)以不可预知的顺序加载和运行。浏览器会并行加载它们,并且可以自由地以任何它想要的顺序运行它们。
多个异步事物之间没有可预测的顺序。如果需要一个可预测的顺序,那么就必须通过注册来自异步脚本的加载通知来编码,并在适当的东西加载时手动排序javascript调用。
动态插入脚本标记时,执行顺序将取决于浏览器。您可以在这篇参考文章中看到Firefox的行为。简而言之,Firefox的新版本默认将动态添加的脚本标记添加到async,除非脚本标记另有设置。
带有async的脚本标签可以在加载时立即运行。事实上,浏览器可能会暂停解析器,不管它正在做什么,然后运行该脚本。所以,它几乎可以在任何时候运行。如果脚本被缓存,它几乎可以立即运行。如果脚本需要一段时间才能加载,那么它可能会在解析器完成后运行。关于async要记住的一件事是,它可以在任何时候运行,而且时间是不可预测的。
A script tag with defer waits until the entire parser is done and then runs all scripts marked with defer in the order they were encountered. This allows you to mark several scripts that depend upon one another as defer. They will all get postponed until after the document parser is done, but they will execute in the order they were encountered preserving their dependencies. I think of defer like the scripts are dropped into a queue that will be processed after the parser is done. Technically, the browser may be downloading the scripts in the background at any time, but they won't execute or block the parser until after the parser is done parsing the page and parsing and running any inline scripts that are not marked defer or async.
下面是那篇文章中的一段话:
脚本插入的脚本在IE和WebKit中异步执行,但是
在Opera和4.0版本之前的Firefox中同步运行。
HTML5规范的相关部分(适用于更新的兼容浏览器)在这里。这里有很多关于异步行为的文章。显然,该规范不适用于您可能需要测试才能确定的旧浏览器(或不符合规范的浏览器)。
引用HTML5规范:
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.
The task that the networking task source 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.
If the element has a src attribute, and the element has been flagged
as "parser-inserted", and the element does not have an async attribute
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 networking task source 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.
If the element does not have a src attribute, and the element has been
flagged as "parser-inserted", and the Document of the HTML parser or
XML parser that created the script element has a style sheet that is
blocking scripts 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.)
Set the element's "ready to be parser-executed" flag. The parser will
handle executing the script.
If the element has a src attribute, does not have an async attribute,
and does not have the "force-async" flag set The element must be added
to the end of the list of scripts that will execute in order as soon
as possible associated with the Document of the script element at the
time the prepare a script algorithm started.
The task that the networking task source places on the task queue once
the fetching algorithm has completed must run the following steps:
If the element is not now the first element in the list of scripts
that will execute in order as soon as possible to which it was added
above, then mark the element as ready but abort these steps without
executing the script yet.
Execution: Execute the script block corresponding to the first script
element in this list of scripts that will execute in order as soon as
possible.
Remove the first element from this list of scripts that will execute
in order as soon as possible.
If this list of scripts that will execute in order as soon as possible
is still not empty and the first entry has already been marked as
ready, then jump back to the step labeled execution.
If the element has a src attribute The element must be added to the
set of scripts that will execute as soon as possible of the Document
of the script element at the time the prepare a script algorithm
started.
The task that the networking task source 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.
Otherwise The user agent must immediately execute the script block,
even if other scripts are already executing.
Javascript模块脚本,type="module"?
Javascript现在支持用这样的语法加载模块:
<script type="module">
import {addTextToBody} from './utils.mjs';
addTextToBody('Modules are pretty cool.');
</script>
或者,带src属性:
<script type="module" src="http://somedomain.com/somescript.mjs">
</script>
所有type="module"的脚本都会自动被赋予defer属性。这将与页面的其他加载一起并行(如果不是内联)下载它们,然后在解析器完成之后按顺序运行它们。
模块脚本也可以被赋予async属性,该属性将尽快运行内联模块脚本,而不是等待解析器完成,也不会等待以相对于其他脚本的任何特定顺序运行异步脚本。
这里有一个非常有用的时间轴图,显示了不同脚本组合的获取和执行,包括本文中的模块脚本:Javascript模块加载。