你的网站为什么总感觉“慢半拍”?
点开一个链接,页面要等一两秒才动——不是你网卡,也不是服务器拖后腿,而是浏览器压根没提前准备。它在那儿干坐着,等 HTML 解析完、JS 执行完、DOM 构建好,才想起来:“哦,这个字体还没加载呢”“那个评论插件的域名我连都没连过”。
Resource Hints 就是来改掉这个习惯的:不等它问,你先告诉它。
Resource Hints到底是什么?四种核心指令详解
Resource Hints 不是黑科技,就是几行 link 标签,写在 <head> 里,给浏览器递个话:“待会儿可能要用这个,你先搭个桥,或者顺手捞一下。”
dns-prefetch:只做 DNS 查询。比如你页面里要加载 https://stats.example.com 的统计脚本,加一句 <link rel="dns-prefetch" href="https://stats.example.com">,浏览器就会趁空闲把域名解析成 IP 地址,省掉后续连接时那几十毫秒。
preconnect:比 dns-prefetch 多走两步——查完 DNS,再建好 TCP 连接,HTTPS 的话连 TLS 握手都做完。相当于把路修通、门打开、钥匙塞进锁孔,就差推门进去了。
prefetch:浏览器空闲时,悄悄下载一个资源(比如下一页的 HTML、某个关键 JS),放进 HTTP 缓存里。等用户真点进去,直接从缓存读,不用再发请求。
prerender:最狠的——浏览器在后台把整个目标页面(HTML + CSS + JS + 渲染树)全跑一遍,用户点链接那一刻,直接切画面。但代价高:吃内存、耗流量、可能触发不该触发的 API。别乱用。
一个真实案例:某电商详情页嵌了第三方评论组件,每次打开都要等 800ms 才开始连评论服务。我们只加了一行 <link rel="preconnect" href="https://comments.api-shop.com" crossorigin>,评论区域出现时间明显提升,用户滑到这儿时,内容已经“蹲好”了。
如何配置?三种主流方法手把手教你
方法一:在 HTML 的 <head> 中直接写 <link> 标签
最直白,也最常用。打开你首页的 HTML 模板,在 <head> 开头附近贴上:
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://cdn.example.com">
适合静态页、模板可控的项目。缺点是得手动维护,大站容易漏。
方法二:通过 HTTP 响应头 Link 发送
后端同学更喜欢这个。Nginx 配置里加一行:
add_header Link "<https://fonts.googleapis.com>; rel=preconnect; crossorigin";
Node.js(Express)里可以:
res.append('Link', '<https://api.example.com>; rel=preconnect');
好处是:HTML 还没到浏览器,提示就已经在路上了,启动时机更早。
方法三:用 JavaScript 动态注入
适用于需要判断用户行为再决定预连的场景。比如鼠标悬停在“立即购买”按钮上时,才去 preconnect 支付网关:
button.addEventListener('mouseenter', () => {
const link = document.createElement('link');
link.rel = 'preconnect';
link.href = 'https://pay.gateway.com';
document.head.appendChild(link);
});
注意:JS 注入晚,效果打折扣。别指望它救首屏。
配置时最容易踩的坑有哪些?
prerender 别碰,除非你真有把握用户 90% 会点那个链接。它会在后台开一个完整渲染进程,吃内存、占带宽、还可能执行副作用代码(比如误发埋点、重复调用登录接口)。
prefetch 和 preload 不是一回事。preload 是给当前页“保命”的资源用的(比如首屏大图、关键 CSS),浏览器会立刻加载;prefetch 是给“下一页”备的,优先级低,空闲时才干活。拿 preload 去预取下一页的 HTML?浏览器会把它当关键资源抢着载,反而拖慢自己。
跨域资源记得配 crossorigin。比如预连 Google Fonts,必须写:
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
不然浏览器会拒绝复用连接,预连等于白干。
顺序有讲究。想加载某个 CDN 上的图片?先 preconnect 到那个域名,再 prefetch 图片地址。如果跳过连接步骤直接 prefetch,浏览器还得临时补个连接,白忙活。
怎么知道我的配置有没有生效?
别猜,看 DevTools。
打开 Chrome,F12 → Network 面板 → 刷新页面。找任意一个第三方请求(比如 fonts.googleapis.com),点开它的 Timing 标签页。如果 “Connection Start” 时间明显靠前,甚至和 HTML 请求几乎同步,说明 preconnect 生效了。
再切到 Application → Frames → Preloads,这里会列出所有被 prefetch 或 prerender 的资源,状态是 “Ready” 还是 “Pending”,一目了然。
Lighthouse 扫描结果里,如果有 “Consider adding preconnect for important third-party origins” 这类建议,也说明你漏了该配的提示。
一个可观察的现象:当你给商品分类页的“女装”链接加上 <link rel="prefetch" href="/category/dress"> 后,鼠标悬停上去,Network 面板里会出现一条灰色的 prefetch 请求,状态是 “Pending”,等你真点进去,它立刻变成“from cache”。
实战中,哪些场景最适合用Resource Hints?
关键第三方资源:字体、统计、客服 SDK、视频播放器——这些不是你家的服务器,但卡住它们,整页就卡。首页 <head> 最顶上,挨个 preconnect 它们的域名。比如:
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>
<link rel="preconnect" href="https://player.vimeo.com" crossorigin>
确定性路径:电商的“加入购物车 → 去结算 → 提交订单”,新闻站的“上一篇/下一篇”,文档站的“下一步”。在当前页直接 prefetch 下一页的 HTML,翻页体验接近 SPA。
懒加载资源的前置准备:首页有个“查看更多商品”按钮,点开才加载瀑布流。那就在页面加载时,对商品图床域名 preconnect,等用户点开,图片请求直接起飞。
轻量交互预测:鼠标悬停在导航菜单项上,大概率是要点进去。这时动态 prefetch 对应页面的 HTML。比全量预取更省,命中率更高。
今天下班前,你能立刻执行的一个优化步骤
打开你公司官网或主力业务页(比如 / 或 /products),用 Chrome 打开,按 F12。
- 切到 Network 面板,勾选 Disable cache,然后 Ctrl+R 刷新;
- 在请求列表里,从上往下扫,找出那些域名不是你自己的请求——比如
fonts.googleapis.com、cdn.jsdelivr.net、sentry.io、你们用的客服系统域名; - 挑出 1~2 个最关键的:它加载慢、影响首屏渲染、或者用户一进来就依赖(比如客服浮窗、实时价格接口);
- 找到这个页面的 HTML 模板(Vue 的
.vue文件、React 的index.html、PHP 的header.php、或者 Nginx 的静态文件),在<head>标签内部、尽可能靠上的位置,贴一行:(如果是字体、JS 等跨域资源,<link rel="preconnect" href="https://刚才记下的域名.com" crossorigin>crossorigin别漏); - 保存,推到测试环境,再走一遍第1步。对比刷新前后,那个第三方请求的 Timing 里,“Connection Start” 是否提前了?如果从 200ms 缩到 20ms,你就成了。
现在,就打开你正在编辑的那个 HTML 文件,加这一行。五分钟后,它已经在跑。