C03 资源提示与性能
摘要:首屏时间的大部分消耗在「发现资源」与「等待连接」两步,而不是解析 HTML。
preconnect、preload、fetchpriority与defer这四类声明,作用是把这两步提前或推后。用错方向时收益为负:预加载不用的资源会挤占带宽,阻塞脚本会推迟首屏。本文给出按关键路径配置的四段代码与三项验证。
关键词:关键渲染路径,preload,preconnect,fetchpriority,阻塞
所属:frontend/html / C-高级 | 上一篇:C02-表单校验进阶 | 下一篇:C04-XSS与CSP
1 引言
页面变慢有两种原因:资源太多,或资源发现得太晚。前者的解法是压缩与裁剪,后者的解法是资源提示——让浏览器在解析到对应标签之前就知道「有个东西要提前拿」。
本文按关键路径的顺序给出四段声明与取舍依据。范围见表 1-1。
| 项 | 本文覆盖 | 本文不覆盖 |
|---|---|---|
| 连接 | dns-prefetch、preconnect |
CDN 与边缘节点选型 |
| 资源 | preload、prefetch、fetchpriority、modulepreload |
打包与代码分割策略 |
| 脚本 | defer、async、type="module" |
框架水合与运行时性能 |
| 字体与图片 | font-display、宽高预留、懒加载边界 |
字体子集化与图片编码 |
2 预备知识
| 项 | 要求 | 核对方式 |
|---|---|---|
| 环境 | A02 的本地服务器 | 能访问 localhost |
| 前置 | B02、B01 | 图片与 head 已掌握 |
| 工具 | Chrome 开发者工具 Performance 与 Network 面板 | 能看到瀑布图与优先级 |
| 文件 | html-practice/perf.html |
编码 UTF-8 |
3 原理与实现
3.1 关键路径与提示位置
浏览器按「建立连接 → 发现资源 → 下载 → 解析 → 渲染」推进,资源提示插在前两步,如图 3-1 所示。
flowchart LR
A["HTML 到达"] --> B["解析 head"]
B --> C["dns-prefetch / preconnect<br/>提前建连"]
B --> D["preload<br/>提前发现关键资源"]
B --> E["脚本 defer / async<br/>调整执行时机"]
D --> F["下载关键 CSS 与字体"]
E --> G["DOMContentLoaded"]
F --> H["首次绘制"]
G --> H
H --> I["可交互"]
图 3-1 关键渲染路径与资源提示的位置
图上可见:提示只改变「什么时候开始下载」,不改变资源体积;体积问题必须靠压缩与裁剪解决。
3.2 四段声明
<!-- 运行环境:Chrome 130+;head 内按需使用 -->
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 1. 提前建连:第三方域名 -->
<link rel="preconnect" href="https://cdn.example.com" crossorigin />
<link rel="dns-prefetch" href="https://cdn.example.com" />
<!-- 2. 提前发现:首屏关键资源 -->
<link rel="preload" href="./assets/fonts/inter.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="./assets/images/hero.avif" as="image" fetchpriority="high" />
<!-- 3. 非首屏资源:空闲时再取 -->
<link rel="prefetch" href="./assets/images/next-page.jpg" as="image" />
<!-- 4. 脚本时机 -->
<script src="./assets/js/app.js" defer></script>
<script src="./assets/js/analytics.js" async></script>
</head>
<body>
<img src="./assets/images/hero.avif" alt="首屏主图" width="1200" height="630" fetchpriority="high" decoding="async" />
<img src="./assets/images/cover.avif" alt="文章配图" width="960" height="540" loading="lazy" decoding="async" />
</body>
四类提示的差异见表 3-1。
| 声明 | 提前做什么 | 过度使用后的代价 |
|---|---|---|
dns-prefetch |
域名解析 | 几乎无代价,可多加 |
preconnect |
DNS + TCP + TLS | 占用连接,超过 4 个反而变慢 |
preload |
下载并缓存指定资源 | 与其它资源抢带宽,未使用会告警 |
prefetch |
空闲时下载下个页面资源 | 流量浪费,弱网下拖慢当前页 |
fetchpriority |
调整同类型资源的优先级 | 全部标 high 等于没有优先级 |
defer |
解析完 HTML 后按顺序执行 | 首屏依赖该脚本时会延后渲染 |
async |
下载完立即执行 | 执行顺序不可控 |
常见指标与对应手段见表 3-2。
| 指标 | 含义 | 主要手段 |
|---|---|---|
| LCP | 最大内容绘制时间 | 首屏图预加载 + fetchpriority="high" |
| CLS | 布局偏移 | 图片与广告位预留宽高 |
| INP | 交互响应 | 减少主线程长任务,脚本 defer |
| TTFB | 首字节时间 | 连接复用、服务端缓存 |
4 验证与讨论
- 打开 Network 面板,勾选 Priority 列,记录首屏图与懒加载图的优先级差异。
- 打开 Performance 面板录制一次加载,查看 LCP 标记落在哪个元素上,是否为首屏图。
- 删除
width/height,重复步骤 2,观察 CLS 是否出现偏移。 - 把
defer改为同步脚本,比较首次绘制时间的变化。
| 检查项 | 预期结果 | 说明 |
|---|---|---|
| 连接复用 | 第三方域名提前建连 | 瀑布图起点提前 |
| 首屏图优先级 | 标记为 High | fetchpriority |
| 懒加载图 | 初始不请求 | loading="lazy" |
| 布局稳定 | CLS 接近 0 | 宽高预留 |
| 脚本不阻塞 | 首屏在脚本下载前已绘制 | defer |
讨论与局限。 preload 的资源若最终未被使用,浏览器会给出未使用告警,且浪费一次请求。另本地开发环境没有网络延迟,资源提示的收益在本地几乎不可见,必须用限速模拟或真实网络验证。
5 常见问题
| 现象 | 原因 | 处理 |
|---|---|---|
| preload 告警未使用 | 资源地址与页面实际请求不一致 | 与 src 完全一致,含 crossorigin 设置 |
| 字体仍闪烁 | 未用 font-display 或 preload 缺失 |
补 font-display: swap 与 preload |
| 首屏图优先级未提升 | 写在了 srcset 的候选上 |
在 img 元素上加 fetchpriority |
| 加了 async 后脚本报错 | 依赖顺序被打乱 | 改 defer 或合并脚本 |
| CLS 偏高 | 图片与占位容器无固定尺寸 | 补宽高或用宽高比容器 |
6 结论
| 序号 | 结论 | 依据 |
|---|---|---|
| 1 | 资源提示改变发现与连接时机,不改体积 | 图 3-1 |
| 2 | preconnect 控制在 4 个以内 |
表 3-1 |
| 3 | 首屏图 fetchpriority="high",其余懒加载 |
表 3-1、3.2 代码 |
| 4 | 布局稳定靠宽高预留,不靠提示 | 表 3-2 |
- 上一篇:C02-表单校验进阶
- 下一篇:C04-XSS与CSP
- 返回:C00-总结 | 科目 README
参考文献
[1] MDN Web Docs · 资源提示,https://developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes/rel/preload(访问于 2026-10-29)
[2] web.dev · 优化 LCP,https://web.dev/articles/optimize-lcp(访问于 2026-10-29)

评论 0
还没有评论,快来抢沙发吧~