Web 性能优化之 dns-prefetch 和 preconnect
# dns-prefetch
当我们打开一个网页后,这个网页后续可能还会使用到其他域的资源,如果我们能提前对该域进行 DNS 解析的话,那是必会减少后续的请求延迟。dns-prefetch
尝试在请求资源之前解析域名。这可能是后面要加载的文件,也可能是用户尝试打开的链接目标。
# 为什么要使用 dns-prefetch?
当浏览器从(第三方)服务器请求资源时,必须先将该 跨源 域名解析为 IP 地址,然后浏览器才能发出请求,此过程称为 DNS 解析。对于打开了与许多第三方的连接的网站,DNS 解析可能会给请求增加明显的延迟,此延迟可能会大大降低加载性能。特别是如果该域的信息不在浏览器或系统的 DNS 缓存中,或者如果 DNS 服务器响应慢的情况下。
dns-prefetch
可帮助开发人员掩盖 DNS 解析延迟。HTML <link>
元素通过设置 rel
属性值为 dns-prefetch
提供此功能。然后在 href
属性中指明要跨源的域名:
# 语法
<link rel="dns-prefetch" href="https://fonts.googleapis.com/" />
# 最佳实践
首先,dns-prefetch
仅对跨源域上的 DNS 查找有效,因此请避免使用它来指向你的站点或域。这是因为,到浏览器看到提示时,你的站点背后的 IP 已经被解析了。
其次,还可以通过使用 HTTP Link 字段将 dns-prefetch
(以及其他资源提示)指定为 HTTP 标头(响应头)之一:
Link: <https://fonts.googleapis.com/>; rel=dns-prefetch
再其次,考虑将 dns-prefetch
与 preconnect
提示配对。dns-prefetch
只执行 DNS 查询,而 preconnect
则是建立与服务器的连接。这个过程包括 DNS 解析,以及建立 TCP 连接,如果是 HTTPS 网站,就进一步执行 TLS 握手。将这两者结合起来,可以进一步减少跨源请求的感知延迟。你可以像这样安全地将它们结合起来使用:
<link rel="preconnect" href="https://fonts.googleapis.com/" crossorigin />
<link rel="dns-prefetch" href="https://fonts.googleapis.com/" />
组合使用这两者 preconnect
和 dns-prefetch
,是因为并非所有浏览器都已经实现了 preconnect
,不支持 preconnect
的浏览器仍然可以通过回退到 dns-prefetch
来获得更多好处。由于这是 HTML 特性,因此容错性很强。如果浏览器也不支持 dns-prefetch
提示(或任何其他资源提示),则网站不会中断,只是不会获得它提供的好处。
# 注意事项
如果页面需要建立与许多第三方域的连接,则将它们预先连接会适得其反。preconnect
提示最好仅用于最关键的连接。对于其他的连接,只需使用 <link rel="dns-prefetch">
即可节省第一步——DNS 查询——的时间。
# preconnect
在速度较慢的网络中建立连接往往需要很长时间,尤其是在安全连接方面。
preconnect
它允许开发者告诉浏览器提前建立到特定域的连接,包括 DNS 解析,TCP 握手,以及可选的 TLS 协商。这样做的好处在于,当用户真正需要从这些域名加载资源时(例如,CSS、JavaScript 文件或者图片),浏览器已经完成了准备工作,可以直接开始资源的传输。这减少了延迟,提高了页面的加载速度。
预连接过程涵盖了多个阶层的网络成本:
- DNS 查找:将域名转换成 IP 地址。
- TCP 握手:建立一条到服务器的确认连接的过程。
- TLS 协商:如果资源通过 HTTPS 加载,还需要进行 TLS 握手以确保通信的安全性。
# 语法
<link rel="preconnect" href="https://example.com">
# 注意事项
虽然 <link rel="preconnect">
消耗的成本不高,但它仍然会占用宝贵的 CPU 时间,尤其是在安全连接上。如果没有在 10 秒内使用连接,此问题尤其糟糕,因为浏览器会关闭连接,浪费所有早期连接工作。