一、背景与问题
在网页性能优化中,脚本的加载和执行方式直接影响页面渲染速度和用户体验。传统 <script>
标签的阻塞行为可能导致页面“白屏”,而 async
和 defer
属性提供了非阻塞的解决方案。本周重点研究二者的差异、适用场景及实际应用。
二、核心概念解析
1. 默认 <script>
的行为
- 阻塞 HTML 解析:浏览器遇到
<script>
标签时,会暂停 HTML 解析,下载并执行脚本,完成后继续解析。 - 问题:大脚本或网络延迟时,显著延长页面渲染时间。
2. async
属性
- 行为:
- 脚本异步下载(与 HTML 解析并行)。
- 下载完成后立即执行,执行时会再次阻塞 HTML 解析。
- 特点:
- 脚本执行顺序不确定(先下载完的先执行)。
- 适用于独立且无依赖的脚本(如统计分析、广告 SDK)。
3. defer
属性
- 行为:
- 脚本异步下载(与 HTML 解析并行)。
- 脚本延迟到 HTML 解析完成后、DOMContentLoaded 事件前 按顺序执行。
- 特点:
- 执行顺序与声明顺序严格一致。
- 适用于依赖 DOM 或其他脚本的场景(如页面初始化逻辑)。
4. 对比表格
属性 | 加载方式 | 执行时机 | 执行顺序 | 适用场景 |
---|---|---|---|---|
默认 | 同步 | 立即执行 | 按声明顺序 | 无 |
async |
异步 | 下载完立即执行 | 不确定 | 独立脚本(如 GA 统计) |
defer |
异步 | HTML 解析后顺序执行 | 按声明顺序 | 依赖型脚本 |
三、示例与验证
代码示例
<script src="script1.js" async></script>
<script src="script2.js" defer></script>
<script src="script3.js"></script>
执行顺序模拟
默认脚本:script3.js 阻塞 HTML 解析,优先执行。
async 脚本:若 script1.js 下载速度快于 HTML 解析,可能先于 defer 脚本执行。
defer 脚本:script2.js 在 HTML 解析完成后按顺序执行。
四、最佳实践
优先使用 defer:确保脚本顺序执行且不阻塞渲染。
谨慎使用 async:仅用于无依赖的第三方脚本。
动态脚本:通过 document.createElement('script') 插入的脚本默认具有 async 行为。
五、兼容性与注意事项
兼容性:
defer 支持所有主流浏览器(包括 IE10+)。
async 不支持 IE9 及以下。
注意点:同时使用 async 和 defer 时,现代浏览器以 async 优先。
附录
MDN 文档
测试 Demo 链接(可选)
text
Copy Code
### 说明
1. ‌**兼容性**‌:此 Markdown 文件可被所有支持 Markdown 的工具(如 Typora、VS Code、GitHub)正确解析。
2. ‌**语法重点**‌:
- 代码块用 ` ````包裹,并指定语言(如 `html`)。
- 表格使用 `|` 分隔列,`---` 分隔表头。
- HTML 标签用反引号包裹避免解析冲突(如 ``<script>``)。