Early Hints如何加速网页加载与提升用户体验
我的写法,亲测靠谱
Early Hints(103 Early Hints)这玩意儿我最早是在一个首屏加载特别慢的项目里试水的。当时用户一打开页面,白屏得能煎蛋,Lighthouse 评分惨不忍睹。后来琢磨着用 Early Hints 提前把关键资源推下去,效果确实立竿见影——首屏快了近 400ms。但中间踩的坑也不少,今天就把我现在用的稳定方案和大家唠唠。
我现在的做法是:在服务端响应 HTML 之前,先发一个 103 响应,把关键 CSS、JS、字体这些资源的 Link 头提前告诉浏览器。注意,只推真正关键的,别一股脑全塞进去,否则适得其反。
以下是我用 Node.js + Express 的实际代码(其他语言逻辑类似):
app.get('/page', (req, res) => {
// 先发 Early Hints
res.writeEarlyHints({
link: [
'</static/main.css>; rel=preload; as=style',
'</static/app.js>; rel=preload; as=script',
'</fonts/inter.woff2>; rel=preload; as=font; type="font/woff2"; crossorigin'
]
});
// 模拟一些异步数据获取(比如查数据库)
setTimeout(() => {
const html =
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/static/main.css">
</head>
<body>
<div id="app">Loading...</div>
<script src="/static/app.js"></script>
</body>
</html>
;
res.send(html);
}, 200);
});
这里有几个关键点:
- 只 preload 真正阻塞渲染的资源:比如主样式、核心 JS、首屏用的字体。图片、非关键 JS 别乱加,会浪费带宽还可能触发浏览器的预加载限制。
- 路径要和 HTML 里的一致:如果 HTML 里写的是
/static/main.css,Early Hints 里也必须完全一样,包括斜杠。不然浏览器会当成两个资源,重复下载。 - 字体必须加
crossorigin:这点我一开始忘了,结果字体没生效,折腾半天才想起来。所有字体 preload 都得带这个属性,哪怕同源。
这几种错误写法,别再踩坑了
我见过也自己踩过不少 Early Hints 的坑,下面这些写法千万别学:
1. 把所有资源都塞进 Early Hints
有次我图省事,把十几个 JS、CSS、图片全推了,结果 Chrome 直接忽略了后面的 Link 头(因为超过内部限制)。更糟的是,有些资源还没被 HTML 引用,浏览器就提前下载了,纯属浪费流量。现在我严格控制在 3~5 个最关键资源。
2. 用相对路径或错路径
// 错!
res.writeEarlyHints({
link: ['<main.css>; rel=preload; as=style']
});
浏览器解析时会基于当前 URL 拼接,但如果你的页面是 /user/profile,那它会去请求 /user/main.css,404 了。必须用绝对路径(以 / 开头)。
3. 忘记设置正确的 as 和 type
比如字体不写 as=font 和 type="font/woff2",浏览器就不知道怎么处理,可能直接忽略。JS 不写 as=script,可能被当成普通 fetch 请求,优先级不对。
4. 在不支持 Early Hints 的环境硬上
不是所有服务器都支持 103 响应。比如老版本 Nginx、某些 Serverless 平台(Vercel 目前还不支持原生 Early Hints)。我之前在本地开发用 Express 没问题,一上线到某个平台就失效了,查了半天才发现平台根本不透传 103。所以上线前务必确认基础设施支持。
实际项目中的坑
除了上面那些,实战中还有几个细节容易翻车:
缓存策略要对齐。Early Hints 推的资源如果缓存时间很短,而 HTML 缓存时间长,用户下次访问时 HTML 从缓存读,但资源又要重新下,反而更慢。我现在统一给关键静态资源设一年缓存(带 hash 文件名),Early Hints 和 HTML 里的引用保持一致。
不要和 HTTP/2 Server Push 混用。虽然 Server Push 也能提前推资源,但它已经被废弃了,而且和 Early Hints 行为冲突。我之前在一个项目里同时开了两个,结果 Chrome 下载了两份 main.css,直接翻车。现在一律只用 Early Hints。
测试要真实环境。本地开发时用 localhost 很难看出效果,因为网络延迟几乎为零。我一般用 WebPageTest 或 Lighthouse 在模拟 3G 网络下跑,才能看到 Early Hints 带来的实际提升。另外,Chrome DevTools 的 Network 面板默认不显示 103 响应,得勾选 “Show all” 才能看到 Early Hints 条目。
还有个小问题:目前 Safari 对 Early Hints 的支持还不完善(截至 2024 年中),所以不能完全依赖它。我的做法是 Early Hints 作为增强,基础体验(比如关键 CSS 内联)依然要做好,保证 Safari 用户也不至于太慢。
要不要用?我的建议
如果你的项目满足以下条件,我建议上 Early Hints:
- 首屏依赖外部 CSS/JS,且无法内联(比如 CMS 系统、多页面应用)
- 服务端能控制 HTTP 响应(Node.js、PHP、Go 等都行,但 Serverless 可能受限)
- 关键资源数量不多(3~5 个以内)
如果只是 SPA,且用了现代打包工具(Vite、Webpack)做了代码分割和预加载,可能收益不大。Early Hints 最适合那种“服务端吐 HTML + 外部静态资源”的传统架构。
最后提醒一句:Early Hints 不是银弹。我见过有人为了用它而重构整个构建流程,结果维护成本飙升,性能提升却微乎其微。**先用 Lighthouse 定位瓶颈,确认是资源发现延迟导致的问题,再考虑 Early Hints**。别为了炫技而加功能。
以上是我踩坑后的总结,希望对你有帮助。Early Hints 虽小,但用对了真能提速。有更好的方案欢迎评论区交流,比如你们在 Cloudflare 或 Nginx 上怎么配的,我也想学学。

暂无评论