在《使用 preload 和 prefetch 预加载关键资源》一文中,介绍了如何提前加载资源文件。今天要介绍的是使用 DNS 预解析(dns-prefetch),提前做跨域的 DNS 解析优化前端性能的方法。

我们知道,当浏览器从(第三方)服务器请求资源时,必须先将该跨域域名解析为 IP 地址,然后浏览器才能发出请求,此过程称为 DNS解析。DNS 解析可以导致请求增加明显的延迟。对于打开了与许多第三方的连接的网站,此延迟可能会大大降低加载性能。

而随着浏览器功能的不断提升,目前主流的浏览器都支持一种叫 dns-prefetch (DNS 的预解析)的技术,通过 dns-prefetch 可帮助开发人员减少 DNS 解析延迟,优化页面资源的加载速度。

什么是 <link rel=”dns-prefetch”> ?

dns-prefetch(DNS预解析),这种资源提示伪指令会尝试在请求资源之前提前解析域名。解析的域名可能是以后加载的(第三方)文件的域名,也可能是用户尝试点击的(第三方)链接目标的域名。

dns-prefetch 浏览器支持情况

浏览器对 dns-prefetch 的支持是非常不错了,主流的浏览器都支持了。

dns-prefetch 的适用场景和注意事项

Chromium 和 Firefox 的关于 DNS Prefetching 的官方文档 有这么一句:

Manual Prefetch

Chromium uses the “href” attribute of hyperlinks to find host names to prefetch. However, some of those hyperlinks may be redirects, for example if the site is trying to count how many times the link is clicked. In those situations, the “true” targeted domain is not necessarily discernible by examining the content of a web page, and so Chromium not able to prefetch the final targeted domain.

上面这段文字包含两个重要信息:

  1. chrome 会自动把当前页面的所有带 href 的 link 的 dns 都 prefetch 一遍;
  2. 需要手动添加link标签的场景是:你预计用户在后面的访问中需要用到当前页面的所有链接都不包含的域名;

所以,假设页面 head 里面有个第三方的 css 链接(例如CDN资源), 在当前页的 head 里加上对应的手动 dns prefetch 实际上并没有好处。因为上面提到了 chrome 会自动把当前页面的所有带 href 的 link 的 dns 都 prefetch 一遍,所以不用特别手动添加处理这类跨域的资源 DNS 预解析。

dns-prefetch(DNS预解析)的适用的场景主要是优化访问跨域资源的DNS解析速度,适用场景有以下几类:

  • 页面包含第三方域名的静态资源,可以使用 DNS 预取;
  • 页面的 JS 中会动态生成的链接包含跳转到第三方域名,可以使用 DNS 预取;
  • 重定向跳转的新域名,如:页面有个A域名的链接,但访问A会重定向到B域名的,可以使用 DNS 预取;

使用 dns-prefetch 也要注意一定,dns-prefetch 仅对跨域的 DNS 查找有效,因此请避免使用它来指向您的站点本身的域名。这是因为,到浏览器会自动在背后的做本域名下的 DNS 解析。

dns-prefetch 调用方式

与之前介绍的 prefetch 和 preload 的调用方式类似,都是使用 标签作为载体,设置 rel 属性为 dns-prefetch,设置 href 属性指定需要 DNS 预取的域名,代码如下:

<link rel="dns-prefetch preconnect" href="//mic-open.mypaas.com.cn">

域名可以写成完整的 URL 地址,也可以用示例中的写法。推荐使用示例中的方式指定域名。

dns-prefetch 可以开来多少性能提升?

当浏览器从(第三方)服务器请求资源时,必须先将该跨域的域名解析为IP地址,然后浏览器才能发出请求。此过程称为DNS解析。虽然DNS缓存可以帮助减少此延迟,但是DNS解析可以为请求增加大量的延迟。对于打开了包含许多第三方的连接或资源员的网站,此延迟可能会大大降低加载性能。

大多数浏览器可以检测并预取页面中包含的超链接中的域名。但是,他们可能找不到由分析和社交共享平台注入的脚本文件和标记中包含的第三方的域名。dns-prefetch 则可以解决跨域DNS解析相关的延迟问题(即,将您的站点域名解析为IP地址所花费的时间),这可能会使站点的页面加载时间减少,从而优化网站性能。

dns-prefetch 的网络消耗是极低极低的,chromium 的官方文档是这么说的:

Each request typically involves sending a single UDP packet that is under 100 bytes out, and getting back a response that is around 100 bytes. This minimal impact on network usage is compensated by a significant improvement in user experience.

翻译:每个请求通常包括发送一个小于100字节的UDP数据包,然后返回大约100字节的响应。用户体验的显著改善弥补了对网络使用的这种最小影响。

Chrome 浏览器使用了 8 个线程专门做 dns prefetching,Chrome 浏览器本身不做 dns 记录的缓存,它是直接从操作系统读 DNS 的。也就是说,直接修改系统的 dns 记录或者 host 是可以直接影响 chrome 的。普遍来说合理的 dns-prefetch 能对页面性能带来 50ms ~ 300ms 的提升。