如果您不是动态加载脚本或将其标记为defer
或async
,则脚本将按照页面中遇到的顺序加载。不管是外部脚本还是内联脚本,它们都按照在页面中遇到的顺序执行。保留外部脚本之后的内联脚本,直到加载并运行它们之前的所有外部脚本为止。
异步脚本(无论如何将其指定为异步脚本)均以不可预测的顺序加载和运行。浏览器以并行方式加载它们,并且可以按任意顺序自由运行它们。
在多个异步事物之间没有可预测的顺序。如果需要一个可预测的顺序,则必须通过注册异步脚本的加载通知并在加载适当的东西时手动排序javascript调用来对它进行编码。
动态插入脚本标签时,执行顺序的行为将取决于浏览器。您可以在本参考文章中了解Firefox的行为。简而言之,较新版本的Firefox会将动态添加的脚本标签默认为异步,除非另行设置了脚本标签。
带有的脚本标签async
可以在加载后立即运行。实际上,浏览器可能会暂停解析器的运行,并运行该脚本。因此,它几乎可以随时运行。如果脚本被缓存,它可能几乎立即运行。如果脚本需要一段时间才能加载,则它可能在解析器完成后运行。要记住的一件事async
是它可以随时运行,并且时间是不可预测的。
带有脚本标记的脚本要defer
等到整个解析器完成后,再按defer
遇到的顺序运行所有标有的脚本。这样,您就可以将几个相互依赖的脚本标记为defer
。它们都将被推迟到文档解析器完成之后,但是它们将按照保留它们的依赖关系的顺序执行。我认为defer
脚本已放入解析器完成处理的队列中。从技术上讲,浏览器可能会随时在后台下载脚本,但是直到解析器解析完页面并解析并运行任何未标记defer
或的内联脚本后,它们才会执行或阻止解析器async
。
这是该文章的引文:
插入脚本的脚本在IE和WebKit中异步执行,但是在Opera和4.0之前的Firefox中同步执行。
HTML5规范的相关部分(适用于较新的兼容浏览器)在此处。那里有很多关于异步行为的文章。显然,此规范不适用于您可能需要测试以确定其行为的旧版浏览器(或格式不正确的浏览器)。
HTML5规范的引文:
然后,必须遵循以下描述情况的第一个选项:
如果该元素具有src属性,并且该元素具有defer属性,并且该元素已被标记为“插入分析器”,并且该元素没有异步属性,则
该元素必须添加到列表的末尾与创建元素的解析器的Document相关联的文档完成解析后将执行的脚本。
一旦获取算法完成,网络任务源将其放置在任务队列上的任务必须设置元素的“准备由解析器执行”标志。解析器将处理执行脚本。
如果该元素具有src属性,并且该元素已被标记为“插入分析器”,并且该元素没有异步属性,则
该元素是创建该元素的分析器的文档的待处理分析阻止脚本。(每个文档一次只能有一个这样的脚本。)
一旦获取算法完成,网络任务源将其放置在任务队列上的任务必须设置元素的“准备由解析器执行”标志。解析器将处理执行脚本。
如果该元素没有src属性,并且该元素已标记为“插入分析器”,并且创建脚本元素的HTML解析器或XML解析器的文档具有阻止脚本的样式表,则该元素为创建元素的解析器文档的暂挂解析阻止脚本。(每个文档一次只能有一个这样的脚本。)
设置元素的“准备解析器执行”标志。解析器将处理执行脚本。
如果该元素具有src属性,没有async属性,并且没有设置“ force-async”标志,则该元素必须添加到将尽快执行的脚本列表的末尾。在准备脚本算法开始时使用脚本元素的文档。
获取算法完成后,网络任务源将其放置在任务队列上的任务必须运行以下步骤:
如果该元素现在不是脚本列表中第一个要按顺序执行的元素,那么该元素将被添加到上面,请将该元素标记为就绪,但在不执行脚本的情况下放弃这些步骤。
执行:执行与该脚本列表中第一个脚本元素相对应的脚本块,这些脚本块将尽快执行。
从将尽快执行的脚本列表中删除第一个元素。
如果此将尽快执行的脚本列表仍然不为空,并且第一项已被标记为就绪,则跳回到标记为执行的步骤。
如果元素具有src属性,则必须将元素添加到将在准备脚本算法开始时尽快执行脚本元素文档的脚本集中。
一旦获取算法完成,网络任务源将放置在任务队列上的任务必须执行脚本块,然后从将尽快执行的脚本集中删除该元素。
否则,即使其他脚本已在执行,用户代理也必须立即执行脚本块。
那么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
属性,该属性将尽快运行内联模块脚本,而不是等到解析器完成后才开始,并且不等待async
相对于其他脚本以任何特定顺序运行脚本。
有一个非常有用的时间表,显示了脚本的不同组合的获取和执行,包括本文中的模块脚本:Javascript Module Loading。