01. HTML Script 引入方式及特性分析
1. 内联脚本(Inline Script)
直接在 HTML 文件中使用 <script>
标签包裹代码:
html
<script>
console.log("内联脚本执行");
</script>
- 特点:
- 立即执行,阻塞 HTML 解析
- 无法缓存,代码复用性差
- 适用于小型代码片段或 PWA 的 Service Worker 注册
2. 外部脚本(External Script)
通过 src
属性引入外部文件:
html
<script src="app.js"></script>
2.1 普通引入
- 执行特点:
- 关键影响:
- 阻塞 DOM 构建和渲染
- 脚本顺序执行(多个脚本按出现顺序加载执行)
2.2 async 属性
html
<script src="app.js" async></script>
核心特性:
- 异步下载,不阻塞 HTML 解析
- 下载完成后立即执行,可能中断渲染
- 执行顺序不固定(先下载完成先执行)
- 适用场景:独立第三方脚本(如统计代码)
执行流程:
2.3 defer 属性
html
<script src="app.js" defer></script>
核心优势:
- 异步下载,不阻塞 HTML 解析
- 延迟到 DOMContentLoaded 事件前顺序执行
- 保证脚本执行顺序(按文档中声明顺序)
- 适用场景:DOM 依赖型脚本
执行时序:
3. 模块化引入(type="module")
html
<script type="module" src="app.js"></script>
特殊行为:
- 默认具有
defer
特性 - 支持 ES6 模块语法(
import/export
) - 可配合
async
使用(此时忽略defer
特性)
模块加载示例:
html<script type="module"> import { init } from './utils.js'; init(); </script>
- 默认具有
4. 动态脚本加载
通过 JavaScript 动态创建脚本:
javascript
const script = document.createElement('script');
script.src = 'app.js';
document.head.appendChild(script);
- 特点:
- 默认具有
async
行为 - 可通过
script.async = false
改为同步加载 - 适用于按需加载场景
- 默认具有
关键对比表格
特性 | 普通脚本 | async | defer | type="module" |
---|---|---|---|---|
执行顺序 | 文档顺序 | 下载顺序 | 文档顺序 | 文档顺序 |
阻塞解析 | 是 | 否 | 否 | 否 |
DOMContentLoaded 前完成 | 不一定 | 不一定 | 是 | 是 |
支持 document.write | 是 | 禁止 | 禁止 | 禁止 |
最佳实践建议
- 主业务逻辑使用
defer
保证 DOM 就绪 - 独立第三方库使用
async
(如 analytics.js) - 关键路径脚本可内联(需控制体积)
- 现代项目优先使用
type="module"
+defer
- 动态加载非关键功能(如图表库)
javascript
// 性能优化示例:优先加载关键资源
const criticalScript = document.createElement('script');
criticalScript.src = 'critical.js';
document.head.prepend(criticalScript);
window.addEventListener('load', () => {
// 延迟加载非关键脚本
const nonCritical = document.createElement('script');
nonCritical.src = 'analytics.js';
nonCritical.async = true;
document.body.appendChild(nonCritical);
});
通过合理使用这些特性,可将页面加载性能优化 20-40%(根据 WebPageTest 实测数据)。需特别注意:async
脚本的执行可能影响 First Contentful Paint
,而 defer
能更好地配合浏览器预加载扫描器工作。