一、资源加载顺序与阻塞机制
1. DOM 构建关键阶段
- domLoading:开始解析接收到的 HTML 字节流
- domInteractive:完成 HTML 解析及 DOM 树构建
- domContentLoaded:DOM 与 CSSOM 均准备就绪,触发事件
- domComplete:所有资源(如图片、脚本)加载完成
2. CSS 与 JS 的阻塞特性
资源类型 | 阻塞行为 | 影响范围 |
---|---|---|
CSS | 阻塞渲染树构建(页面空白),不阻塞 DOM 解析 | 后续 JS 执行被阻塞 |
JS | 阻塞 DOM 构建和渲染,立即执行 | 后续 HTML 解析暂停 |
典型场景 :
若 CSS 文件在 JS 前声明且延迟返回,即使 JS 先下载完成,仍需等待 CSS 解析完毕才能执行
二、<script>
标签加载模式对比
属性 | 加载行为 | 执行时机 | 顺序保证 |
---|---|---|---|
无属性 | 同步加载,阻塞 HTML 解析 | 立即执行 | 按文档顺序 |
defer | 异步加载,不阻塞解析 | DOMContentLoaded 前按序执行 | 按加载顺序 |
async | 异步加载,不阻塞解析 | 加载完成立即执行 | 无顺序 |
特殊场景:动态脚本
ini
const script = document.createElement('script');
script.src = 'a.js';
script.async = false; // 强制按文档顺序执行:ml-citation{ref="8" data="citationList"}
document.body.appendChild(script);
三、开发实践与场景选择
1. 使用 defer
的场景
- 需操作 DOM 元素(如表单初始化)
- 脚本间存在依赖关系(如库文件 + 业务逻辑)
- 示例:
xml
<script src="vue.js" defer></script>
<script src="app.js" defer></script> <!-- 保证 vue.js 先执行 -->
2. 使用 async
的场景
- 独立无依赖脚本(如数据分析 SDK)
- 优先级较低的后台任务(如错误日志上报)
- 示例:
xml
<script src="analytics.js" async></script> <!-- 不阻塞页面渲染 -->
四、性能优化建议
-
关键路径优化
- 首屏必要 JS 使用内联或无属性加载,非关键脚本使用
defer/async
- 首屏必要 JS 使用内联或无属性加载,非关键脚本使用
-
资源优先级控制
- 通过
<link rel="preload">
提前加载核心 CSS/JS
- 通过