在网页开发中,JavaScript 的加载和执行方式直接影响页面性能。默认情况下,浏览器在解析 HTML 页面时遇到 <script> 标签会暂停页面渲染,直到脚本加载并执行完毕。这会显著影响页面加载速度,尤其是在加载大型 JS 文件时。
为了解决这个问题,JavaScript 提供了多种延迟加载(Lazy Loading)的方式,以优化页面性能。
✅ 一句话总结
JavaScript 延迟加载的核心目的是避免阻塞页面渲染,提升首屏加载速度。常见的方法包括
defer、async、动态创建script、setTimeout和将脚本放在页面底部。
✅ 一、延迟加载的 5 种方式详解
🔹 1. defer 属性
<script src="script.js" defer></script>
- ✅ 特点:
- 脚本在HTML 文档解析完成后再执行;
- 不会阻塞 HTML 解析;
- 多个带有
defer的脚本按顺序执行;
- 📌 适用场景:
- 脚本依赖页面 DOM;
- 需要多个脚本顺序执行;
- ⚠️ 注意:
- 不适用于内联脚本(某些浏览器可能支持);
🔹 2. async 属性
<script src="script.js" async></script>
- ✅ 特点:
- 脚本异步加载,不阻塞 HTML 解析;
- 一旦脚本加载完成,立即执行;
- 多个
async脚本执行顺序不确定;
- 📌 适用场景:
- 脚本不依赖页面 DOM;
- 脚本之间没有依赖关系;
- ⚠️ 注意:
- 适合独立的脚本,如统计脚本、广告脚本;
🔹 3. 动态创建 DOM 脚本标签(推荐)
window.addEventListener('load', function () {
const script = document.createElement('script');
script.src = 'script.js';
document.body.appendChild(script);
});
- ✅ 特点:
- 完全控制脚本加载时机;
- 可监听
load、error等事件; - 脚本加载完成后自动执行;
- 📌 适用场景:
- 需要在特定事件(如滚动、点击)后加载脚本;
- 实现按需加载或懒加载;
- ⚠️ 注意:
- 不会阻塞页面渲染;
- 更加灵活,但需要手动管理加载逻辑;
🔹 4. 使用 setTimeout 延迟加载
setTimeout(() => {
const script = document.createElement('script');
script.src = 'script.js';
document.body.appendChild(script);
}, 3000); // 3秒后加载
- ✅ 特点:
- 通过定时器控制脚本加载时间;
- 可以延迟到页面渲染完成后再加载;
- 📌 适用场景:
- 需要延迟非关键脚本;
- 控制加载节奏;
- ⚠️ 注意:
- 可能造成用户体验延迟;
- 不推荐用于关键功能脚本;
🔹 5. 将脚本放在文档底部(最基础方式)
<body>
<!-- 页面内容 -->
<script src="script.js"></script>
</body>
- ✅ 特点:
- 脚本在 HTML 文档解析完成后才加载;
- 不会阻塞页面渲染;
- 📌 适用场景:
- 简单项目或不支持现代加载方式的浏览器;
- ⚠️ 注意:
- 不如
defer或async灵活; - 无法控制加载顺序或异步行为;
- 不如
✅ 二、五种方式对比表格
| 方式 | 是否阻塞 HTML 解析 | 是否异步加载 | 是否等待文档解析完成 | 是否顺序执行 | 适用场景 |
|---|---|---|---|---|---|
defer | 否 | 是 | 是 | 是 | 依赖 DOM、需顺序执行 |
async | 否 | 是 | 否 | 否 | 独立脚本、不依赖 DOM |
| 动态创建 script | 否 | 是 | 是(可控制) | 是(按添加顺序) | 按需加载、高级控制 |
setTimeout | 否 | 是 | 是(可控制) | 是(按添加顺序) | 延迟加载、非关键功能 |
| 放在 body 底部 | 否 | 否 | 是 | 是 | 简单项目、兼容性需求 |
✅ 三、一句话总结
使用
defer和async是最简单、标准的延迟加载方式;动态创建 script 标签提供了更高的灵活性;而setTimeout和底部加载适用于简单或兼容性场景。根据脚本依赖关系和加载时机选择合适的策略,是优化页面性能的关键。
💡 进阶建议
- 使用
defer保证多个脚本顺序执行; - 使用
async加载非关键脚本; - 使用动态加载实现按需加载(如滚动加载、点击加载);
- 使用
onload事件确保脚本加载完成后再执行相关操作; - 在 Vue、React 等框架中,使用动态导入(
import())实现代码分割和懒加载;