预扫描器仅扫描首层html字节流,不执行js、不解析嵌套超6层或惰性容器内的资源,关键资源须直出在初始html中且置于语义标签内;fetchpriority和preload必须显式声明于或开头附近,否则信号失效。

预扫描器只认首层 HTML 字节流,不执行 JS
浏览器在开始构建 DOM 之前,会启动一个轻量级的预加载扫描器(Preload Scanner),它不解析 JS、不展开嵌套、不识别条件渲染——只对初始 HTML 字节流做一次快速线性扫描。这意味着:document.createElement('img')、innerHTML、JSX 表达式里生成的 <img> 标签,预扫描器根本看不到。
常见错误现象包括:
- 首屏大图始终是
Medium优先级,LCP 候选元素迟迟不发起请求 -
link rel="preload"声明了字体却仍 FOUC(Flash of Unstyled Content) - Next.js 的
<image fetchpriority="high"></image>在{isLoaded && <image>}</image>中完全失效
关键结论:所有需要被提前发现的资源,必须出现在服务端直出的首层 HTML 中,且不能藏在 JS 控制的条件块或深层嵌套里。
DOM 深度超过 6 层,预扫描器直接截断
Chromium 的预扫描器会在 DOM 树深度达到 6 层时主动停止向下读取子节点。这不是性能限制,而是设计决策——它只扫描“可信结构”,连续多层 <div> 嵌套会被当作噪声跳过。
<p>典型失效场景:</p>
<ul><li>
<code><picture></picture> 内部的 <source></source> 能被识别,但整个 <picture></picture> 若被包在 <div class="lazy-load-wrapper"> 里,且该 wrapper 没有 <code>src 或 loading="eager",预扫描器就当它不存在
<details></details>、<dialog></dialog>、<slot></slot> 这类惰性容器中的资源,几乎 100% 被忽略v-if 或 *ngIf 渲染的关键图片,在初始 HTML 里压根没标签,预扫描器无从响应建议把关键资源放在语义化标签内(如 <main></main>、<article></article>),它们本身会提升子元素资源的探测可信度。
fetchpriority 和 preload 必须在首层显式声明
fetchpriority 不是运行时 API,它只在 HTML 解析阶段被读取一次;link rel="preload" 也必须出现在 或 开头附近,才能被及时拾取。一旦被包裹进组件模板、JSX 表达式或条件注释中,信号就彻底失效。
注意兼容性差异:
-
fetchpriority="high"只对<img>和<iframe></iframe>生效,且仅 Chromium 119+ 支持 - Safari 17.2+ 仅部分识别
<img>的fetchpriority,Firefox 完全忽略 -
link rel="preload"必须带as属性(如as="style"、as="font"),否则浏览器无法判断资源类型,降级为普通<link>
别在 <style></style> 块里用 @import 加载 CSS——预扫描器不解析 CSS 内容,@import 是 CSSOM 阶段才触发的串行阻塞行为。
<meta charset> 必须在前 1024 字节内,且位置靠前
浏览器解析 HTML 时,会先用默认编码(通常是 UTF-8)扫描前 1024 字节寻找 <meta charset>。如果没找到,就会按默认编码继续解析;后续即使出现 <meta charset="UTF-8">,也无法修正已错解的字节。
真实踩坑点:
-
<meta charset="UTF-8">放在<title></title>后面,而<title></title>内容含中文,可能导致标题乱码 - 文件开头存在 BOM(
EF BB BF)或注释,挤占了有效扫描空间 - 服务器返回的 HTTP
Content-Type头未声明charset=utf-8,进一步增加解析不确定性
最稳妥写法是把 <meta charset="UTF-8"> 放在 的第一行,确保它落在前 512 字节内——这是多数浏览器实际生效的安全阈值。











