请说说`<script>`、`<script async>`和`<script defer>`的区别
在前端开发中,<script>
、<script async>
和 <script defer>
都用于在 HTML 文档中嵌入 JavaScript 代码,但它们在加载和执行脚本的方式上有所不同,从而影响页面的渲染性能和行为。
1. <script>
(默认行为):
- 加载和执行: 浏览器解析到
<script>
标签时,会立即停止解析 HTML,下载脚本文件,然后执行脚本。执行完毕后,浏览器才会继续解析剩余的 HTML。 - 阻塞: 这是阻塞式的加载方式,意味着在脚本下载和执行完成之前,页面渲染会被阻塞。如果脚本文件很大或网络速度慢,会导致页面出现明显的延迟,用户体验不佳。
- 顺序执行: 脚本会按照它们在 HTML 中出现的顺序依次下载和执行。
2. <script async>
:
- 加载和执行: 浏览器解析到
<script async>
标签时,会异步下载脚本文件,不会阻塞 HTML 解析。脚本下载完成后,浏览器会立即暂停 HTML 解析并执行脚本,执行完毕后再继续解析 HTML。 - 非阻塞: 异步加载,不会阻塞页面渲染。
- 执行顺序不确定: 多个带有
async
属性的脚本的执行顺序是不确定的,它们可能会以任何顺序执行,取决于哪个脚本先下载完成。因此,async
适用于不依赖于其他脚本或不影响页面结构的独立脚本,例如统计分析脚本。
3. <script defer>
:
- 加载和执行: 浏览器解析到
<script defer>
标签时,会异步下载脚本文件,不会阻塞 HTML 解析。脚本下载完成后,会等待 HTML 解析完成,并在DOMContentLoaded
事件触发之前执行。 - 非阻塞: 异步加载,不会阻塞页面渲染。
- 顺序执行: 带有
defer
属性的脚本会按照它们在 HTML 中出现的顺序执行。这对于需要操作 DOM 或依赖其他脚本的脚本非常有用。
总结:
特性 | <script> |
<script async> |
<script defer> |
---|---|---|---|
加载方式 | 同步 | 异步 | 异步 |
阻塞 HTML 解析 | 是 | 否 | 否 |
执行时机 | 立即 | 下载完成后立即执行 | HTML 解析完成后,DOMContentLoaded 事件触发前 |
执行顺序 | 按顺序 | 不确定 | 按顺序 |
适用场景 | 需要立即执行的脚本,但会阻塞页面渲染 | 独立脚本,例如统计分析脚本 | 需要操作 DOM 或依赖其他脚本的脚本,例如初始化代码 |
示例:
<!DOCTYPE html>
<html>
<head>
<title>Script Example</title>
</head>
<body>
<script src="script1.js"></script> <!-- 默认,阻塞 -->
<script async src="script2.js"></script> <!-- 异步,执行顺序不确定 -->
<script defer src="script3.js"></script> <!-- 异步,按顺序执行 -->
</body>
</html>
选择哪种方式取决于脚本的功能和它们之间的依赖关系。如果脚本之间没有依赖关系且不影响页面渲染,可以使用 async
。如果脚本需要操作 DOM 或依赖其他脚本,最好使用 defer
。 尽量避免使用默认的 <script>
方式,除非脚本必须立即执行并且可以接受阻塞页面渲染。