原文链接:General HTML performance considerations, from web.dev。翻译时有删改。
当我们在浏览器地址栏中输入 URL,敲击回车键时,浏览器会发起一个 GET 请求来获取网页内容。而对网页的第一个请求是请求 HTML 资源。因此,如何尽快响用 HTML 文档就成为了一个关键指标。
有一个性能指标,叫 Time to First Byte (简称 TTFB),是用来描述 HTML 文档相应速度的。TTFB 就是字面上表达的意思:即从浏览器发起 GET 请求直到接收到 HTML 文档的第 1 个 字节,中间所经历时间。当然,我们希望 TTFB 越低越好。
本文中,我们就将介绍几种方法,教大家如何提升 HTML 文档的响用速度。
开始吧。
最小化重定向次数
当请求网页资源时,有时会发生重定向,像 301(Moved Permanently)、302(Moved Temporarily) 这样的响应码都与重定向有关。
重定会降低网页加载速度,因为它向需要浏览器基于返回的 Location 字段要再额外多发一次 HTTP 请求。
因此,为了更快的响应速度,我们应该尽量减少网页的重定向次数。
重定向地址可以是否同源分同源重定向(Same-origin redirects)和跨源重定向(Cross-origin redirects)。同源重定向发生在站内,是可以控制的;跨源重定向则发生在站外,是不受我们控制的。
跨源重定向通过由像广告、URL 短地址服务、搜索引擎跳转统计等这样的三方服务中使用。
虽然跨源重定向不受控制,但我们也能找到优化点。比如:当三方服务引流到本站后,链接是否还会发生重定向 ------包括协议重定向(HTTP 到 HTTPS)、尾路径分隔符重定向(example.com/page/
到 example.com/page
)等。
缓存 HTML 响应
虽然现在 HTML 中会包含一些对其他静态资源的引用,但依然是支持缓存的。
目前缓存 HTML 有 2 个方案,分别针对 2 个不同场景。
第一个场景就是静态站点网页,这个场景下网页一般主要是静态呈现内容,典型的案例像博客、文档站点。这种静态网页很适合强缓存。
所谓"强缓存"就是请求服务器时,如果响应里有类似 Cache-Control: max-age=300
的字段出现时,浏览器会缓存网页内容。这里的 max-age 是用于定义当前的资源的有效期的(单位是秒(s)),对于静态 HTML 资源来说,5 分钟是一个安全的选择。在有效期内,当再次访问这个 HTML 时,会直接使用本地浏览器的缓存,不会额外再发请求了。
第二个场景针对是复杂网页,即网页中包含很多对其他静态的链接。这类较常更新的网页就适合使用协商缓存。
所谓"协商缓存"就是请求服务器时,如果响应里有类似 Cache-Control: no-cache
的字段出现时,浏览器会缓存网页内容。同时,跟随 Cache-Control 一起返回的,一般还会有 ETag 和 Last-Modified 字段。
ETag(也叫 entity tag) 的值,是作为唯一表示所请求资源的标识符,通常使用资源内容的哈希值。
bash
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
在下一次用户再次访问这个 HTML 时,会先校验当前缓存是否有效。这次请求中,会发送 If-None-Match/Etag、Last-Modified-Since/Last-Modified 内容,如果后端校验没有改变,则返回 304(Not Modified)状态码,浏览器还使用上次缓存的内容,否则返回 200 状态码,浏览器使用新返回的网页内容。
当然,协商缓存的新鲜度校验的请求本身也是有开销的。所以,是否需要协商缓存,也要基于站点特点进行权衡。
如果你不在意 HTML 的延迟,同时还要确保绝对安全,也可以完全不去缓存 HTML 内容。
测算后端响应时间
如果你没有对 HTML 进行缓存,那么网页响应时间则是高度依赖于托管提供商和后端所采用的技术栈。
相比而言,动态生成的网页比静态网页有更高的 TTFB。不过,纯客户端渲染的页面又受到不可预测的客户端环境影响。因此,如果在后端能尽快生成并响应网页,也是一种可以提升用户体验的方式。
我们通常可以采用返回响应头 Server-Timing
的方式,来公开服务器上所花费的时间。
arduino
Server-Timing: auth;dur=55.5, db;dur=220
Server-Timing 标头的值可以包含多个指标以及每个指标所耗费的时间。这些数据可以通过 Navigation Timing API 进行收集并分析。
以上面的数据为例:
auth;dur=55.5
:表示在用户身份验证这个阶段话费了 55.5 毫秒(ms)db;dur=220
:表示在数据库访问上花费了 220 毫秒
我们可以根据这些测算到的数据,检查我们的托管基础设施,是否有足够资源处理网站流量;或是检查数据库系统,是否可以进行访问优化。
使用文本压缩算法
基于文本的响应(例如:HTML、JavaScript、CSS 和 SVG 图像)通常会进行压缩,来减少网络传输大小,便于更快下载。目前最广泛使用的压缩算法是 gzip 和 Brotli。Brotli 比 gzip 算法有 15% 到 20% 的提升。
大多数网络托管提供商通常会自动设置压缩,如果你能自己设置,则最好:
- 尽可能使用 Brotli 算法。所有主流浏览器都支持 Brotli 算法,相对 gzip,它有很大的改进。如果你网站的大量用户还在使用旧浏览器,那么可以考虑使用 gzip 算法做后备
- 压缩文件的大小要适中。较小的文件(小于 1kb)不能最大程度的发挥的算法优势
- 理解动态压缩(dynamic compression)和静态压缩(static compression)。动态压缩是指请求资源时再压缩,静态压缩是指提前压缩文件。动态压缩会增加服务器响应时间,静态压缩消除了压缩资源本身的延迟。静态资源应该使用静态压缩,而 HTML 资源(尤其是每个用户登录后动态生成的资源)应该采用动态压缩。
使用 CDN
CDN 全名叫"Content Delivery Network",即"内容分发网络"。它是一种分布式服务器网络,缓存源服务器中的资源,然后再选择最靠近的用户的边缘服务器提供资源文锦,从而减少往返时间(round-trip time (RTT)),让用户能更快获得内容。
以上,我们就讲完了优化 HTML 文档响应速度、提升 TTFB 指标的几个方案。
总结
本文讲述了如何提升 HTML 文档响用速度的几种方案。包括:
- 最小化重定向次数
- 缓存 HTML 响应(强缓存 & 协商缓存)
- 测算后端响应时间(Server-Timing 响应头 + Navigation Timing API)
- 使用文本压缩算法(动态压缩 & 静态压缩),以及
- 使用 CDN
这几个方案从不同维度影响着响用速度以及 TTFB 指标值。
更多关于优化 TTFB 的指标,大家可以参考《Optimize Time to First Byte》 这篇文章了解。
当然,TTFB 不是衡量网页加载速度的唯一指标。不过,高 TTFB 指标会直接拉低后续指标,比如:Largest Contentful Paint (LCP) 和 First Contentful Paint (FCP)。也就是说,针对 HTML 的接收优化只是开始,远没有结束。
接下来,我们将继续介绍其他方面的优化措施。期待你的关注,感谢阅读,再见。