结论先给:fetchpriority 的核心原则只有一条——每个页面只把真正 LCP 的那一个资源抬成 high,其余该降的都降成 low,多个 high 等于没有 high。

帖子断在第四步,我接着补完,并补充几个容易出现问题的地方:

<!-- 首屏大图抬升 -->
<img src="/hero.avif" fetchpriority="high" width="1200" height="600">
<!-- 首屏外、统计打点这类降到 low -->
<img src="/below-fold.jpg" fetchpriority="low" loading="lazy">
<script src="/analytics.js" fetchpriority="low" defer></script>

注意 fetchpriority 只影响“同一类型资源之间”的相对排序,不会让一张图超过 CSS 或阻塞脚本;想真正提前,仍要用 preload。

几个补充要点:

  1. ES 模块用 modulepreload,不要用 preload as="script"。<link rel="modulepreload" href="/js/main.js"> 会连带预解析整个 import 依赖图,直接消除模块逐层发现的层级式请求;而用 preload 预载模块只会拉第一个文件,后续 import 仍要靠浏览器逐层发现。
  2. 预载样式表要切换 rel:<link rel="preload" as="style" onload="this.onload=null;this.rel='stylesheet'"> 再配 <noscript> 兜底,否则同一 CSS 会请求两次。
  3. 响应式图预载用 imagesrcset / imagesizes,不要写死 href,不然移动端会下载桌面版大图。
  4. type 一定要写,尤其字体 type="font/woff2":浏览器不支持该格式会直接跳过,省掉一次无用的预载。

最后一个坑:HTTP/2 多路复用下 preload 的收益确实会打折,但对“CSS 里才被发现”的字体和背景图依然有效,不要因为看到“HTTP/2 不需要 preload”的说法就全删。