dns-prefetch通过提前执行dns查询,将跨域资源加载链路中的dns阶段前置,在首次访问且无缓存时节省20–120ms(弱网可达150ms+);需用协议相对url、置于顶部且早于对应资源标签,禁用拦截扩展后通过timing面板验证效果。

减少DNS解析耗时,是网络层性能优化中“投入小、见效快”的关键一环。dns-prefetch本身不直接缩短首屏时间,但它能提前抢出20–120ms的空档——尤其在首次访问、弱网、跨域资源多的场景下,这几十毫秒常是卡点突破的黄金窗口。
它到底省在哪?不是“总时间”,而是“链路启动时机”
浏览器加载一个跨域资源(比如CDN上的CSS)默认要串行走完:DNS → TCP → TLS → HTTP请求。其中DNS查询常是第一个阻塞点。dns-prefetch的作用,就是把DNS这一步“拎出来提前干”,让后续真正发起请求时,DNS结果已在系统缓存中 ready-to-use。
- 典型收益落在20–120ms区间:4G弱网下实测可达150ms+,本地DNS或DoH环境下可压至10ms以内
- 这个收益只在「用户首次访问该域名 + 本地无任何层级缓存」时真实生效;缓存命中时DNS时间为0,是正常状态,不是优化失败
- 别拿整页LCP或FCP对比“加/不加dns-prefetch”——JS执行、布局计算等噪声会掩盖真实收益;应专注单个跨域请求的Timing面板中“DNS Lookup”阶段是否提前且耗时下降
写对了才起效:三个硬性规则不能破
很多团队加了标签却没收益,问题几乎都出在基础写法上。
-
href必须用协议相对URL:写成
//cdn.example.com,而不是https://cdn.example.com或http://cdn.example.com。否则在HTTP页面里HTTPS写法会失败,部分Safari版本直接忽略整个标签 -
只支持域名,不支持路径或通配符:
//cdn.example.com/js/main.js和//*.example.com都会被浏览器静默忽略 -
多个独立域名需分别声明:比如同时用到
fonts.googleapis.com和fonts.gstatic.com,就得写两条,不能合并或省略
放对位置,才算“来得及”
浏览器是流式解析HTML的,dns-prefetch必须出现在「首个依赖它的跨域资源标签之前」。
- 例如页面第5行是
<link rel="stylesheet" href="https://cdn.example.com/main.css">,那么<link rel="dns-prefetch" href="//cdn.example.com">就得放在第1~4行,越靠前越好 - 丢在里、用JS动态插入、或塞在之后但跨域资源标签之前的位置不够,都会失效——解析器已经往下跑了,来不及触发预解析
- 建议统一放在顶部,之后、其他资源引入之前
别让它白忙活:排除干扰,验证真实效果
实测前务必清理干扰项,否则看到的可能是假象。
- 禁用uBlock Origin、Privacy Badger等广告/隐私拦截扩展,它们可能主动屏蔽dns-prefetch请求
- 用Chrome DevTools → Network → Timing标签页,过滤目标资源,观察其“DNS Lookup”阶段是否明显左移、耗时缩短
- 清空浏览器缓存、关闭页面再重开,确保测试的是“首次无缓存”场景;反复刷新后DNS时间为0,属预期行为











