1. 预解析的核心目标
浏览器在正式解析(Parsing)HTML 前,会启动一个轻量级的 预解析器(Pre-Parser),快速扫描文档内容,实现:
- 提前发现并加载关键资源(如 CSS、JavaScript、图片)。
- 推测性构建部分 DOM 结构,减少主解析器的等待时间。
- 优化网络请求的优先级,避免资源加载阻塞渲染。
2、具体步骤
- 快速扫描:预解析器逐字节扫描 HTML,识别 资源标签(如<script>、<link>、<img>)
- 推测性构建DOM:预解析器尝试构架简化的DOM结构,供主解析器后续填充
- 主解析器接管:主解析器基于预解析结果继续处理,跳过已扫描的部分,直接填充或修正 DOM
- 主解析器追上时停止:当主解析器处理到预解析器已扫描的位置时,预解析器退出。
3、预解析的触发条件与限制
(1)触发条件:
- HTML 文档开始加载时自动启动。
- 遇到 <script async> 或 <link preload>等标签时增强预加载。
(2)无法预解析的情况:
- 内联JS会强制主解析器暂停。
- 同步脚本(无async/defer)会阻塞预解析和主解析。
- 主解析器暂停时,预解析器也会被迫停止(因为预解析器需要与主解析器保持同步,避免预测错误)。
4、主解析器暂停时预解析器的两种情况:
(1)同步脚本导致的暂停
- 主解析器必须立即下载并执行 脚本(可能修改 DOM)。
- 预解析器强制停止:因为脚本可能通过 document.write()动态插入标签,预解析器必须等待主解析器执行完毕才能保证预测准确性。
(2)async脚本执行导致的暂停
- 主解析器暂停执行脚本,但预解析器继续扫描。
- 原因:async 脚本不会通过 document.write()修改 DOM(现代规范已废弃此用法),且其执行时间极短,预解析器可安全继续工作。
5. 关注资源优先级
- 预解析器会根据资源类型分配优先级:
- 高优先级:CSS、字体、首屏图片。
- 低优先级:非首屏图片、异步脚本。
拓展:
1、资源下载的过程:
触发下载的时机(预解析器扫描+主解析器处理)—>网络请求的生命周期(检查缓存—>建立连接(如果没有缓存)—>发送请求—>接收响应)
2、资源优先级的设置作用:
- 预解析器在快速扫描 HTML 时,会为发现的资源分配初始优先级
- 解析器不直接控制下载,而是由 浏览器网络栈 根据优先级调度下载任务,保证关键路径资源快速就位
3、主解析器和预解析器的步调:
预解析器在扫描到同步脚本时,会停止,等到主解析器走到这个脚本执行完脚本后,两个解析器才同时开始往后走,避免脚本修改后续DOM导致预测错误