async、defer 和 module 属性的比较
这些属性都用于控制 JavaScript 脚本的加载和执行行为,以下是它们的详细比较:
async 属性
- 加载行为 :异步加载脚本,不阻塞 HTML 解析(执行会阻塞)
- 执行时机:脚本下载完成后立即执行(可能在 HTML 解析完成前)
- 执行顺序:不保证多个 async 脚本的执行顺序(先下载完的先执行)
- 适用场景:不依赖 DOM 或其他脚本的独立脚本(如统计分析)
defer 属性
- 加载行为:异步加载脚本,不阻塞 HTML 解析
- 执行时机:脚本在 HTML 解析完成后、DOMContentLoaded 事件前按顺序执行
- 执行顺序:保持多个 defer 脚本在文档中的顺序
- 适用场景:需要操作 DOM 或有依赖关系的脚本
module 属性
-
加载行为:默认行为类似 defer(除非同时使用 async)
-
执行时机:
- 作为模块时默认 defer
- 加上 async 时行为类似普通 async 脚本
-
特殊行为:
- 启用 ES6 模块语法
- 自动应用严格模式
- 有独立的模块作用域
- 支持跨域请求和 CORS
- 会延迟到所有导入模块解析完成才执行
-
适用场景:使用 ES6 模块系统的现代 JavaScript 代码
组合使用
<script type="module">
:等同于 defer<script type="module" async>
:异步加载,下载完立即执行(不保证顺序)
对比表格
属性/行为 | async | defer | module (默认) | module + async |
---|---|---|---|---|
加载是否阻塞解析 | 否 | 否 | 否 | 否 |
执行时机 | 下载完立即执行 | DOM 解析完成后 | DOM 解析完成后 | 下载完立即执行 |
保持顺序 | 否 | 是 | 是 | 否 |
模块系统 | 否 | 否 | 是 | 是 |
最佳实践:现代开发推荐使用 <script type="module">
以获得模块化的好处,同时保持 defer 的有序执行特性。