资源优先级与 Priority Hints:精准控制浏览器加载策略

HTMLPAGE 团队
15 分钟阅读

从 preload、prefetch、preconnect 到 fetchpriority 属性,系统讲解如何指导浏览器优先加载关键资源,加快首屏、优化 LCP 与 FID,避免"样式堵塞渲染、脚本堵塞解析"。

#Resource Loading #Priority Hints #Browser Optimization #Performance #Core Web Vitals

资源优先级与 Priority Hints:精准控制浏览器加载策略

浏览器有自己的资源加载优先级策略,但这个策略通常不是为你的应用优化的。结果经常是:

  • 关键样式表被非关键脚本延迟了
  • 首屏字体比首屏图片更慢加载
  • 某个第三方脚本抢占了关键资源的带宽

幸好,现代浏览器给了开发者很多工具来"教导"它正确的优先级。


1. 浏览器的默认加载优先级

浏览器不是随意加载资源的,有一套隐形的优先级:

资源类型默认优先级典型用途
HTML最高页面骨架
CSS渲染阻塞
同步脚本关键逻辑
字体文本显示
异步脚本分析、追踪
图片最低视觉内容

问题是,这套优先级对你的应用不一定适用。比如:

  • 首屏的关键字体比下面的普通图片更重要
  • 某个脚本看起来是"助手",实际上是首屏交互必须

所以你需要手动调整。


2. preload:声明关键资源

<link rel="preload"> 告诉浏览器"这个资源我马上要用":

<!-- 关键的 CSS -->
<link rel="preload" href="/critical.css" as="style">
<link rel="stylesheet" href="/critical.css">

<!-- 首屏字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- 首屏关键脚本 -->
<link rel="preload" href="/critical-lib.js" as="script">

什么时候用 preload:

  • 首屏展示的字体文件
  • 关键性能路径上的脚本(不是异步脚本)
  • 重要的背景图片(如果在 CSS 中而不是 HTML 中定义)

注意:preload 不是"异步加载",而是"提高优先级"。资源依然可能在渲染时被需要。


3. prefetch:提前加载"可能需要"的资源

<link rel="prefetch"> 的意思是"用户下一步可能需要这些":

<!-- 用户可能会点击下一页 -->
<link rel="prefetch" href="/next-page.js">

<!-- 用户可能会悬停到这个 tab -->
<link rel="prefetch" href="/dashboard-data.json">

特点:

  • 使用浏览器的空闲时间加载(不竞争带宽)
  • 优先级最低,不会影响关键资源
  • 如果用户离开页面,加载会被中断

什么时候用:

  • 路由预加载
  • 用户下一步可能访问的数据
  • 相关资源(比如评论组件的资源)

避免过度 prefetch:如果全页面都 prefetch,反而会浪费带宽。


4. preconnect:提前建立连接

某些资源来自第三方域名(API、CDN、字体服务)。每次首次请求都要经历 DNS lookup、TCP 握手。

<link rel="preconnect"> 可以提前完成这些:

<!-- 提前连接字体服务 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

<!-- 提前连接 API -->
<link rel="preconnect" href="https://api.example.com">

效果是隐形但有效的,通常能节省 100-300ms。

注意:preconnect 会占用系统连接数,不要滥用。通常 3-4 个第三方域就够了。


5. dns-prefetch:纯 DNS 查询加速

如果你只想加速 DNS 查询(不建立完整连接):

<link rel="dns-prefetch" href="https://analytics.example.com">

这比 preconnect 更轻量,适合次要资源。


6. fetchpriority:细粒度的加载优先级(新特性)

HTML 5 新标准 fetchpriority 可以在 <script><link><img> 标签上直接设定优先级:

<!-- 最高优先级:关键脚本 -->
<script src="/webpack.js" fetchpriority="high"></script>

<!-- 低优先级:非关键分析脚本 -->
<script src="/analytics.js" fetchpriority="low" async></script>

<!-- 首屏关键图片 -->
<img src="/hero.jpg" fetchpriority="high">

<!-- 下面的图片可以延迟 -->
<img src="/secondary.jpg" fetchpriority="low" loading="lazy">

兼容性:Chrome 96+, Edge 96+, Opera 82+(2024 年底主流浏览器都支持了)。


7. 实战案例:优化一个"较差"的页面

现状

  • 首屏 LCP 4.5s(目标 2.5s)
  • 关键字体延迟加载
  • 分析脚本竞争带宽

改进清单

<!-- 1. preload 关键字体 -->
<link rel="preload" href="/fonts/Inter-Medium.woff2" as="font" type="font/woff2" crossorigin>

<!-- 2. preconnect 第三方源 -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- 3. 关键 CSS 直接内联或 preload -->
<link rel="preload" href="/critical.css" as="style">

<!-- 4. 高优先级关键脚本 -->
<script src="/app.js" fetchpriority="high"></script>

<!-- 5. 低优先级分析脚本 -->
<script src="/gtag.js" fetchpriority="low" async></script>

<!-- 6. 首屏图片设置高优先级,其他用 lazy -->
<img src="/hero.jpg" fetchpriority="high">
<img src="/secondary.jpg" loading="lazy">

预期提升

  • 字体加载提前 800ms
  • 关键资源带宽竞争减少
  • LCP 从 4.5s 降低到 2.8s

8. 常见误区

误区 1:盲目 preload 所有资源

preload 有成本,多了反而拖累性能。只 preload 关键路径上的资源。

误区 2:与 async/defer 混淆

  • async:加载时不阻塞,执行时阻塞渲染
  • defer:加载不阻塞,执行延迟到 DOM 解析完
  • fetchpriority:优先级,不改变加载和执行时机

误区 3:忘记处理第三方脚本

分析、广告、实时通讯脚本通常来自第三方。给它们用 fetchpriority="low"


9. 测量与监控

用 Performance API 验证优化效果:

// 监控字体加载时间
performance.measure('font-load', 'navigationStart', 'responseEnd')

// 看资源加载顺序
const entries = performance.getEntriesByType('resource')
entries.forEach(entry => {
  console.log(`${entry.name}: ${entry.duration.toFixed(0)}ms`)
})

关键是要看优化前后的 LCPFID,而不是虚荣指标。


10. 最佳实践清单

  • 识别首屏关键资源(通常是字体、关键 CSS、某些脚本)
  • 为关键资源使用 preload
  • 为第三方域名使用 preconnect or dns-prefetch
  • fetchpriority 标记关键 vs 非关键资源
  • 为下一页资源使用 prefetch(如果有路由)
  • 定期测量 LCP、FID,验证改进
  • 避免过度使用 hint,维持 3-5 个关键优化

内链阅读