标准答案

  1. 普通 script 会阻塞 HTML 解析。浏览器遇到它会暂停构建 DOM,先下载并执行脚本,执行完再继续解析。
  2. defer 会并行下载脚本,不阻塞 HTML 解析,等文档解析完成后按页面中的顺序执行。
  3. async 也会并行下载,但下载完会立即执行,可能打断解析,多个 async 脚本之间没有顺序保证。
  4. type="module" 是模块脚本,默认行为接近 defer,会按模块依赖图加载,并且有模块作用域和自动严格模式。
  5. 实际开发里,业务主入口通常用 defer 或 module;独立统计、广告这类第三方脚本更适合 async;有依赖顺序的脚本不要用 async 串联。

题目解析

  • 普通 script:阻塞解析,适合极少数必须立即执行的脚本。
  • defer:并行下载,DOM 解析完成后按顺序执行,适合大多数业务脚本。
  • async:并行下载,下载完立即执行,适合统计、广告、独立第三方脚本。
  • type="module":按模块图加载,默认延迟执行,模块作用域独立,自动严格模式。

defer 脚本会按它们在文档中的出现顺序执行;async 谁先下载完谁先执行;module 脚本会先解析依赖图,执行时遵守模块依赖关系。

如果脚本之间有依赖关系,不要用 async 串联它们。

代码示例

业务入口脚本通常使用 defer 或 module,第三方统计更适合 async。

HTML
<script src="/legacy-critical.js"></script>
<script defer src="/app.js"></script>
<script async src="https://example.com/analytics.js"></script>
<script type="module" src="/main.js"></script>

常见误区

  • 认为 async 一定比 defer 更快。async 可能更早执行,但会打断解析,且顺序不可控。
  • 认为 type="module" 和普通 script 只有语法差异。模块脚本还有作用域、严格模式、CORS 和依赖解析差异。
  • 把依赖 DOM 的脚本放 head 里又不加 defer,导致读取不到节点。

作者信息