likes
comments
collection
share

Web 性能优化之通过资源提示指导浏览器更好加载资源

作者站长头像
站长
· 阅读数 2

原文链接:Assist the browser with resource hints, from web.dev。翻译时有删改。

资源提示是一种开发者人工指导浏览器提前执行某些操作,来提高加载性能的方案。最早引入的资源提示是 preconnectdns-prefetch,后面又增加了 prelod 和 Fetch Priority API。

资源提示通常在 HTML <head> 元素中以 HTML attribute 形式进行指定(也会通过 HTTP 头的,不过并不常见,本文也就不介绍了)。

好了,现在开始吧。

preconnect

preconnect hint 会告诉浏览器预先建立跟另一个域下的连接。

以下是未使用 preconnect 的资源在加载时,通过 Chrome DevTools 的 Network 面板中观察到的可视化连接耗时展示。

Web 性能优化之通过资源提示指导浏览器更好加载资源

红框中的时间是与跨域服务器建立连接所耗费的时间,preconnect 可以通过更快地建立连接来缓解这种情况,而不会延迟到在发现跨域资源时再建立连接。

<link rel="preconnect" href="https://example.com">

preconnect 通常用于站点静态资源的加载,一般情况下这些静态资源会托管在 CDN 服务商那里。如果页面上存在大量跨域资源,就比较适合使用 preconnect。

preconnect 的一个常见用例是 Google 字体。从 Google 复制的字体使用代码如下(会发现使用了 preconnect 连接预建立):

<!-- preconnect 加速 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- 页面某处引入字体资源 -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
  1. 首先,我们会从 fonts.googleapis.com 域名下载字体声明 CSS 文件(@font-face {}
  2. 然后,字体声明 CSS 文件内部会加载来自 fonts.gstatic.com 域名下的字体文件

Web 性能优化之通过资源提示指导浏览器更好加载资源

这里的 crossorigin atrribute 除了限制跨域 Cookie 发送之外,最主要的是在下载字体文件时,能够复用之前打开的连接,避免建立新的连接。

dns-fetch

虽然尽早打开与跨域服务器的连接可以显着缩短初始页面加载时间,但如果一个网页中存在很多要建立的跨域服务器连接,这种做法就不太合理了。

如果你担心过度使用 preconnect,那么可以使用成本低得多的 dns-prefetch hint。

顾名思义,dns-prefetch 不会建立与跨域服务器的连接,而只是提前执行 DNS 查找,将域名解析成 IP 地址。

<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://fonts.gstatic.com">

DNS 查找的成本相对较低。因此在导航到您认为用户可能会访问的其他网站的链接的场景,它可能是比 preconnect 更合适的选择。

dnstradamus 就是这样一种工具,它使用 JavaScript 自动执行此操作,并在指向其他网站的链接滚动到用户视口时使用 Intersection Observer API 将 dns-prefetch 提示注入当前页面的 HTML。

import { dnstradamus } from "dnstradamus";

document.addEventListener("DOMContentLoaded", function () {
  dnstradamus({
    observeChanges: true
  });
});

preload

preload 用于预加载页面中用到的资源。

<link rel="preload" href="/lcp-image.jpg" as="image">

这些资源主要是指访问后期出现的一些关键资源。包括字体文件,通过 @import 导入的 CSS 文件或是会影响 LCP 指标 的 CSS background-image 引用的图片资源。

以上这些资源有一个共同特点,就是在页面初始渲染时,无法被预加载扫描程序发现的。

与 preconnect 类似,如果您要预加载 CORS 资源(例如字体),则 preload 指令需要 crossorigin 属性,否则浏览器会下载 2 次这个资源。

<link rel="preload" href="/font.woff2" as="font" crossorigin>

在前面的 HTML 代码段中,指示浏览器使用 CORS 请求预加载 /font.woff2——即使 /font.woff2 与当前网页位于同一域中。

值得注意的是:与 preconnect 类似,preload 指令是一种非常强大的性能优化。不过也面临着可能被过度使用、抢占带宽的风险,从而对页面加载速度产生负面影响。

prefetch

prefetch 的作用与 preload 类似,都是用于预加载资源的。不过,被指定为 preload 的资源加载优先级较高,被指定为 prefetch 的资源加载优先级较低。

<link rel="prefetch" href="/next-page.css" as="style">

之所以有加载优先级的差异,是因为被指定为 prefetch 的资源是推测性的、将来不一定会访问到

如果你在统计网站上大多数用户是在使用的流程后,想要提升这部分用户访问性能,那么就可以使用 prefetch 预加载那些未来用户可能用到的资源,减少页面加载时间。

不过,如果未来网站用户习惯改变,那么 prefetch 的资源可能也要做响应的调整。这也是使用 prefetch 时需要注意的地方,避免预取资源被闲置。

Fetch Priority API

跟前面几个“无中生有”的优化方案相比,Fetch Priority API 其实是“对现有浏览器加载策略进行修改”。

Fetch Priority API 是通过 fetchpriority attribute 使用的,这个属性可以在 <link><img><script> 元素上应用。

<div class="gallery">
  <div class="poster">
    <img src="img/poster-1.jpg" fetchpriority="high">
  </div>
  <div class="thumbnails">
    <img src="img/thumbnail-2.jpg" fetchpriority="low">
    <img src="img/thumbnail-3.jpg" fetchpriority="low">
    <img src="img/thumbnail-4.jpg" fetchpriority="low">
  </div>
</div>

重要提示:fetchpriority attribute 在用于改善页面的 LCP 图片时特别有效。通过使用这个 attribute 提高 LCP 图像的优先级,你可以相对轻松地改进页面的 LCP。

默认情况下,图片是以较低优先级下载的。在布局时,如果发现图片在初始视口内,那么就可以将它的优先级增加。

在上述 HTML 代码段中,fetchpriority 指导浏览器以高优先级下载较大的 LCP 图片,而缩略图则以较低优先级下载即可。

总结

本文介绍了几种人工干预、指导浏览器进行资源加载的方案,以期换来页面性能的提升。

本系列至此,我们做了针对 HTML、关键渲染路径中涉及到的资源(<head> 中的 CSS 和 JavaScript)和资源提示这 3 类通用优化手段的介绍。

接下来,我们还会对页面中经常出现的一些典型资源类型做单独介绍,分析其特定的优化方案。

首先要介绍的是图片的优化(Image performance),敬请期待。

感谢你的阅读,再见。