在HTML中,` `标签可以通过`defer`和`async`属性来改变脚本的加载和执行行为。两者都是异步加载脚本,即它们不会阻塞HTML解析,但在执行时机上有所不同。
相同点:
- 两者都告诉浏览器可以异步加载脚本,即脚本的加载不会阻塞HTML的解析。
- 两者都只适用于外部脚本(即使用`src`属性的脚本)。
区别:
-
**执行顺序**:
- `async`:脚本一旦加载完成就会立即执行。多个`async`脚本的执行顺序无法保证,先加载完成的先执行。
- `defer`:脚本会按照它们在文档中出现的顺序执行,并且会在DOMContentLoaded事件之前执行(但实际可能会有所延迟,具体要看浏览器和脚本加载情况)。
-
**执行时机**:
- `async`:异步加载,加载完成后立即执行,因此可能会阻塞DOM的解析(尽管加载不阻塞,但执行可能会)。
- `defer`:异步加载,但会等到整个文档解析完成(DOM构建完成)后,在DOMContentLoaded事件之前按顺序执行。
使用场景:
- `async`适用于那些不依赖其他脚本的独立脚本,例如统计代码、广告脚本等。它们不需要等待其他脚本,也不被其他脚本依赖,执行顺序无关紧要。
- `defer`适用于需要按顺序执行且不阻塞文档解析的脚本,例如依赖DOM元素的脚本或者有依赖关系的多个脚本。
示例:
<!-- 使用async -->
<script async src="script1.js"></script>
<script async src="script2.js"></script>
<!-- 可能script2先加载完,那么就先执行script2 -->
<!-- 使用defer -->
<script defer src="script1.js"></script>
<script defer src="script2.js"></script>
<!-- 即使script2先加载完,也会等待script1执行后再执行script2 -->
注意:
- 如果同时使用`async`和`defer`,在现代浏览器中会遵循`async`的行为,而忽略`defer`。
- 没有`src`属性的内联脚本(即直接在标签中写JavaScript代码)使用`async`或`defer`会被忽略。
流程图:
浏览器解析HTML遇到脚本时的行为:
- 没有`async`或`defer`:立即加载并执行脚本,阻塞HTML解析。
- 有`async`:异步加载,加载完成后立即执行(可能阻塞HTML解析,因为执行是同步的)。
- 有`defer`:异步加载,延迟到文档解析完成后按顺序执行。
为了更直观,可以看下面的流程图:
正常脚本(没有defer或async):
HTML解析 -> 遇到脚本 -> 停止解析,加载脚本 -> 执行脚本 -> 继续解析
async脚本:
HTML解析 -> 遇到脚本 -> 异步加载脚本(不阻塞解析) -> 脚本加载完成 -> 停止解析,执行脚本 -> 继续解析
defer脚本:
HTML解析 -> 遇到脚本 -> 异步加载脚本(不阻塞解析) -> 继续解析直到完成 -> 然后按顺序执行所有defer脚本
总结:
- `async`和`defer`都是异步加载,但执行时机不同。
- `async`是无序的,加载完就执行;`defer`是有序的,并且等到DOM解析完成后才执行。
希望这能帮助你理解它们的区别!
评论