预扫描器不执行js,仅线性扫描html字节流;它只识别src等静态属性,无视srcset、js动态插入、css url()、template及深层嵌套内容,且遇阻塞脚本或超1kb内联脚本即终止。

预扫描器根本不会执行 JS,只扫 HTML 字节流
浏览器在开始构建 DOM 前,会启动一个轻量级的预扫描器(Preload Scanner),它不解析 JS、不执行任何脚本、不递归嵌套、也不识别条件渲染逻辑。它只是从 HTML 字节流开头起,逐字符向前扫描,找 <link rel="preload">、<img src>、<script src></script> 这类显式标签。
这意味着以下写法全无效:
-
<img>—— 没有src,预扫描器直接跳过 -
{isHeroLoaded && <img src="hero.jpg">}(JSX/模板语法)—— 服务端没输出该标签,预扫描器根本看不到 -
<template><img src="hero.jpg"></template>—— 预扫描器不进入<template></template>内部 -
<div style="background-image: url('hero.jpg')"></div>—— CSS 中的url()完全不在扫描范围内
首屏 LCP 图片必须带真实 src 且出现在 HTML 前 10KB 内
预扫描器遇到未加 defer 或 async 的同步 <script></script>,或内联脚本体积超过 ~1KB,就会立刻终止扫描。所以关键资源标签必须物理位置靠前。
确保 LCP 图片满足这三点:
-
<img src="/hero.webp" style="max-width:90%" style="max-width:90%">——src必须是可访问的真实 URL,不能是空字符串或占位符 - 标签需出现在
结束后、首个阻塞脚本之前;实测中,HTML 前 10KB 是安全窗口 - 必须带
width和height属性(HTML 属性,非 CSS),否则布局引擎无法提前预留空间,导致 CLS 并延迟 LCP 判定
<link rel="preload"> 必须配对 as 和 crossorigin
<link rel="preload"> 是唯一能绕过 HTML 结构限制、强制提前发起请求的机制,但它极易静默失效。
常见失效组合:
-
<link rel="preload" href="/inter.woff2">—— 缺as="font",浏览器当普通 fetch 处理,Priority 降为Low -
<link rel="preload" href="/inter.woff2" as="font">—— 缺crossorigin,Chrome 120+ 默认拒绝加载,控制台可能无报错但字体不生效 -
<link rel="preload" href="/hero.jpg" as="image" fetchpriority="high">——fetchpriority在此场景锦上添花,但若href和最终<img src>路径不完全一致(比如大小写、查询参数不同),缓存不命中,仍会重复下载
fetchpriority="high" 不是万能钥匙,仅 Chromium 有效且需配合使用
fetchpriority="high" 仅在 Chromium 112+(Chrome/Edge 112+)中生效,Safari 和 Firefox 完全忽略。它不是提速开关,只是向调度器发一个“插队”提示。
真正起效的前提很具体:
- 只能用于
<img>和<iframe></iframe>标签,对background-image、content: url()、JS 创建的元素无效 - 必须和真实
src共存,单独加属性不触发任何请求 - 不能滥用:多个
fetchpriority="high"会让浏览器降级为统一High队列,反而稀释关键图的调度权重 - 若同一资源已用
<link rel="preload">加载,则fetchpriority不再参与优先级决策
最易被忽略的一点:预扫描器只读取 HTML 字节流中的初始声明,所有依赖 JS 注入、CSS 解析、或深层嵌套结构的资源信号,它一律无视——这不是 bug,是设计使然。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











