1. 浏览器加载顺序基础
-
HTML 文件从上到下解析
浏览器解析 HTML,遇到标签就处理,构建 DOM 树。
-
遇到
**<script>**标签时默认行为默认情况下,浏览器遇到
<script>标签会暂停 HTML 解析,去加载并执行该 JS 脚本,执行完成后继续解析 HTML。 -
遇到 CSS 文件时,会先加载 CSS,构建 CSSOM,然后渲染页面
2. <script> 标签的几种常见写法及加载顺序影响
2.1 默认 <script src="..."></script>(无属性)
- 浏览器遇到脚本标签时会阻塞 DOM 解析,先下载并执行脚本,执行完成后继续解析后面的 HTML。
- 这会导致页面渲染变慢,尤其脚本较大时。
2.2 带 defer 属性的 <script defer src="..."></script>
- 脚本会异步下载,但会延迟执行,直到 HTML 完全解析完毕后,才按顺序执行所有 defer 脚本。
- 适合依赖 DOM 完全构建完毕的脚本。
- 多个 defer 脚本执行顺序和它们在 HTML 中的出现顺序一致。
2.3 带 async 属性的 <script async src="..."></script>
- 脚本异步下载,下载完成后立即执行,不保证执行顺序,且执行时会暂停 HTML 解析。
- 适合不依赖 DOM 或其他脚本的独立脚本。
- 多个 async 脚本的执行顺序是不确定的。
2.4 内联 <script> 标签(无 src)
- 浏览器解析到内联脚本时,立即执行,然后继续解析 HTML。
3. JS 与 HTML 文件的加载顺序常见场景
| 情况 | HTML 解析 | 脚本下载 | 脚本执行 | 页面渲染 | 备注 |
|---|---|---|---|---|---|
内联 <script> | 阻塞,立即执行 | 无下载 | 立即执行 | 脚本执行后继续 | 适合短脚本 |
<script src="..." > | 阻塞,暂停解析 | 同步下载 | 同步执行 | 脚本执行后继续 | 会阻塞页面,影响性能 |
<script defer src="..."> | 不阻塞,继续解析 | 异步下载 | HTML解析完成后按顺序执行 | 脚本执行后渲染 | 推荐加载顺序敏感的脚本 |
<script async src="..."> | 不阻塞,继续解析 | 异步下载 | 下载完成立即执行 | 脚本执行时会暂停HTML解析 | 不保证执行顺序,适合独立脚本 |
4. 具体示例
<!DOCTYPE html><html><head> <script src="a.js"></script> <!-- 解析到这里,暂停,下载a.js,执行a.js,继续 --> <script src="b.js" defer></script> <!-- 下载b.js异步,执行延后 --> <script src="c.js" async></script> <!-- 下载c.js异步,下载完成立即执行 --></head><body> <h1>标题</h1> <script> console.log('内联脚本执行'); </script></body></html>执行顺序可能是:
- a.js(阻塞执行)
- 内联脚本
- c.js(async,随时执行)
- b.js(defer,页面解析完后按顺序执行)
5. 建议实践
- 放JS文件于页面底部
**<body>**结束前,避免阻塞页面渲染。 - 使用
**defer**加载依赖 DOM 的脚本,保证执行顺序且不阻塞。 - 使用
**async**加载独立脚本,提高页面加载速度。 - 内联小脚本适用于页面早期逻辑,如设置变量或小型初始化。