优化基于文本的资源的编码和传输大小

除了消除不必要的资源下载之外,提高网页加载速度的最佳方法是优化和压缩剩余资源,从而最大限度地缩减总下载文件大小。

数据压缩入门指南

设置好网站以避免下载任何未使用的资源后,下一步是压缩浏览器必须下载的任何剩余的符合条件的资源。根据资源类型(文本、图片、字体等),您可以选择许多不同的技术:可在 Web 服务器上启用的通用工具、针对特定内容类型的预处理优化,以及需要开发者输入的资源特定优化。

若要实现最佳性能,需要结合使用以下所有技术:

  • 压缩是指使用较少的位对信息进行编码的过程。
  • 消除不必要的数据始终能带来最佳效果。
  • 压缩技术和算法有很多种。
  • 您需要使用各种技术才能实现最佳压缩效果。

减小数据大小的过程称为数据压缩。许多人贡献了算法、技术和优化,以提高压缩比、压缩速度以及各种压缩算法所需的内存。

对数据压缩的完整讨论远远超出了本指南的范围。不过,您有必要从宏观层面了解压缩的运作方式,以及可用于缩减网页所需各种素材资源大小的技术。

为了说明这些技巧的核心原则,我们以优化一种仅为本示例而发明的简单短信格式为例:

# Below is a secret message, which consists of a set of headers in
# key-value format followed by a newline and the encrypted message.
format: secret-cipher
date: 08/25/16
AAAZZBBBBEEEMMM EEETTTAAA
  1. 消息可以包含任意注释(有时称为评论),这些注释以“#”为前缀。注释不会影响消息的含义或行为。
  2. 消息可能包含标头,这些标头是显示在消息开头的键值对(在上面的示例中以 ":" 分隔)。
  3. 消息携带文本载荷。

如何缩减之前消息的大小(从 200 个字符开始)?

  1. 此注释很有趣,但不会影响消息的含义。 在传输消息时消除。
  2. 有一些很好的技术可以高效地对标头进行编码。例如,如果您知道所有消息都有“格式”和“日期”,则可以将这些内容转换为短整数 ID 并仅发送这些 ID。不过,这可能并不正确,因此最好暂时不要更改此设置。
  3. 载荷仅包含文本。虽然我们不知道它的内容到底是什么(显然,它使用的是 "secret-cipher"),但仅从文本来看,其中就存在大量冗余。也许您可以只计算重复字母的数量,并以更高效的方式对其进行编码,而不是发送重复的字母。例如,"AAA" 会变为 "3A",表示包含三个 A 的序列。

结合使用这些技术可产生以下结果:

format: secret-cipher
date: 08/25/16
3A2Z4B3E3M 3E3T3A

新消息的长度为 56 个字符,这意味着您将原始消息压缩了 72%。这可是一笔不小的费用!

这是一个简单的示例,展示了压缩算法如何有效地减小基于文本的资源的传输大小。实际上,压缩算法比上例所示的要复杂得多。在网络上,压缩算法可用于大幅缩短资源的下载时间。通过对基于文本的资源应用压缩,网页可以减少加载资源的时间,从而让用户能够更快地看到这些资源的效果。

缩减:预处理和特定于上下文的优化

此处讨论的第一种技术是缩小化。虽然精简并非严格意义上的压缩算法,但它是一种移除源代码中不必要和冗余字符的方法,可使资源更易于人类阅读。不过,这种可读性对于在正式版网站上保持相应源代码的功能而言并非必需,并且可能会延迟网页上资源的加载。

缩小化是一种特定于内容的优化,可显著减小所交付资源的大小,最好在构建和部署过程中应用这些优化。例如,打包器是一种常用的软件,可在将新的生产代码部署到网站之前自动缩减资源。

压缩冗余或不必要数据的最佳方法是将其清除。 不过,您不能随意删除数据。不过,在某些情况下,如果我们对数据格式及其属性有特定于内容的了解,则可以在不影响载荷实际含义或功能的情况下,显著减小载荷的大小。

<html>
  <head>
    <style>
      /* awesome-container is only used on the landing page */
      .awesome-container {
        font-size: 120%;
      }

      .awesome-container {
        width: 50%;
      }
    </style>
  </head>
  <body>
    <!-- awesome container content: START -->
    <div>
      This is my awesome container, and it is <em>so</em> awesome.
    </div>
    <!-- awesome container content: END -->
    <script>
      awesomeAnalytics(); // Beacon conversion metrics
    </script>
  </body>
</html>

请考虑之前的 HTML 代码段及其包含的三种不同的内容类型:

  1. HTML 标记。
  2. 用于自定义网页呈现效果的 CSS。
  3. JavaScript,用于支持互动和其他高级网页功能。

每种内容类型都有不同的有效内容规则、不同的注释指定规则等。不过,剩下的问题是“如何减小此网页的大小?”

  • 代码注释是开发者的最佳帮手,但浏览器不需要它们!去除 CSS (/* ... */)、HTML (<!-- ... -->) 和 JavaScript (// ...) 注释可减少网页及其子资源的总传输大小。
  • “智能”CSS 压缩器可能会注意到,我们使用了一种效率低下的方式来定义 .awesome-container 的规则,并会将这两个声明合并为一个,而不会影响任何其他样式,从而节省更多字节。对于大量 CSS 规则,移除此类冗余可以累积起来,但可能无法积极应用,因为选择器通常需要在不同上下文(例如媒体查询中)重复使用。
  • 空格和制表符是 HTML、CSS 和 JavaScript 中的开发者便利功能。 其他压缩器可以去除所有制表符和空格。与其他去重技术不同,这种优化可以相当激进地应用,只要这些空格或制表符对于网页的呈现不是必需的即可。例如,您需要保留 HTML 文档中文字运行中的空格,因为它们可确保用户实际看到的内容具有可读性。
<html><head><style>.awesome-container{font-size:120%;width:50%}</style></head><body><div>This is my awesome container, and it is <em>so</em> awesome.</div><script>awesomeAnalytics()</script></body></html>

应用上述步骤后,网页从 516 个字符减少到 204 个字符,节省了大约 60% 的空间。当然,这种格式的可读性并不高,但并不需要可读性高才能使用。借助现代开发实践,您还可以将格式良好且易于阅读的源代码版本与您交付给生产环境的经过良好优化的代码分开。结合使用源映射(可提供转换后的生产代码的易读表示形式,让您更轻松地排查生产环境中的 bug),您既可以获得良好的开发者体验,又可以优化性能以提升用户体验。

上一个示例说明了一个重要问题:通用压缩器(例如,旨在压缩任意文本的压缩器)可以很好地压缩上一个示例中的网页,但它永远不会知道要剥离注释、折叠 CSS 规则或进行数十种其他特定于内容的优化。因此,预处理、缩小化和其他情境感知优化非常重要。

同样,上述技术不仅适用于基于文本的素材资源,还可扩展到其他类型的素材资源。图片、视频和其他类型的内容都包含各自形式的元数据和各种载荷。例如,每当您使用相机拍摄照片时,其文件通常会嵌入许多额外信息:相机设置、位置信息等。根据您的应用,此数据可能至关重要(例如,照片分享网站),也可能完全无用。您应考虑是否值得移除。实际上,此元数据可能会为每张图片增加多达数十 KB 的大小。

简而言之,作为优化资源效率的第一步,请先建立不同内容类型的资源清单,然后考虑可以应用哪些特定于内容的优化来缩减其大小。然后,在确定这些优化项后,将它们添加到 build 和发布步骤中,以实现这些优化项的自动化,确保每次向正式版发布新版本时都能始终如一地应用这些优化项。

使用压缩算法进行文本压缩

减少基于文本的资源大小的下一步是对其应用压缩算法。此方法更进一步,会在将基于文本的载荷发送给用户之前,积极搜索其中的可重复模式,并在这些载荷到达用户浏览器后对其进行解压缩。这样一来,这些资源会进一步大幅减少,下载速度也会更快。

  • gzip 和 Brotli 是常用的压缩算法,在基于文本的资源(CSS、JavaScript、HTML)上表现最佳。
  • 所有新式浏览器都支持 gzip 和 Brotli 压缩,并且会在 Accept-Encoding HTTP 请求标头中通告对这两种压缩格式的支持。
  • 您必须配置服务器以启用压缩。网络服务器软件通常会默认启用模块来压缩基于文本的资源。
  • 通过调整压缩级别,可以对 gzip 和 Brotli 进行微调,以提高压缩率。对于 gzip,压缩设置的范围为 1 到 9,其中 9 为最佳。对于 Brotli,此范围为 0 到 11,其中 11 为最佳。不过,压缩设置越高,所需的时间就越长。对于动态压缩(即在请求时压缩)的资源,中间范围内的设置往往可在压缩比率和速度之间取得最佳平衡。不过,可以进行静态压缩,即提前压缩响应,因此可以针对每种压缩算法使用最激进的压缩设置。
  • 内容分发网络 (CDN) 通常会自动压缩符合条件的资源。CDN 还可以为您管理动态和静态压缩,让您无需再担心压缩方面的问题。

gzipBrotli 是常见的压缩器,可应用于任何字节流。在底层,它们会记住文件的部分先前检查过的内容,然后尝试以高效的方式查找和替换重复的数据片段。

在实践中,gzip 和 Brotli 在基于文本的内容上表现最佳,对于较大的文件,通常可实现高达 70-90% 的压缩率。不过,如果使用其他算法(例如大多数采用无损或有损压缩技术的图片格式)压缩的素材资源运行这些算法,效果几乎没有提升。

所有现代浏览器都会在 Accept-Encoding HTTP 请求标头中通告对 gzip 和 Brotli 的支持。不过,托管服务提供商有责任确保网络服务器配置正确,以便在客户端请求时提供压缩资源。

文件 算法 未经压缩的大小 压缩后的大小 压缩比
angular-1.8.3.js Brotli 1,346 KiB 256 KiB 81%
angular-1.8.3.js gzip 1,346 KiB 329 KiB 76%
angular-1.8.3.min.js Brotli 173 KiB 53 KiB 69%
angular-1.8.3.min.js gzip 173 KiB 60 KiB 65%
jquery-3.7.1.js Brotli 302 KiB 69 KiB 77%
jquery-3.7.1.js gzip 302 KiB 83 KiB 73%
jquery-3.7.1.min.js Brotli 85 KiB 27 KiB 68%
jquery-3.7.1.min.js gzip 85 KiB 30 KiB 65%
lodash-4.17.21.js Brotli 531 KiB 73 KiB 86%
lodash-4.17.21.js gzip 531 KiB 94 KiB 82%
lodash-4.17.21.min.js Brotli 71 KiB 23 KiB 68%
lodash-4.17.21.min.js gzip 71 KiB 25 KiB 65%

上表显示了 Brotli 和 gzip 压缩可为一些知名的 JavaScript 库节省的流量。节省的存储空间介于 65% 到 86% 之间,具体取决于文件和算法。为供参考,我们对 Brotli 和 gzip 的每个文件都应用了最高压缩级别。尽可能优先使用 Brotli 而不是 gzip。

启用压缩是最简单且最有效的优化措施之一。如果您的网站未利用此功能,那么您将错失大幅提升用户体验的良机。幸运的是,许多 Web 服务器都提供默认配置来启用这项重要的优化,尤其是 CDN,能够非常有效地实现这项优化,从而平衡压缩速度和压缩比。

如需快速查看压缩效果,请打开 Chrome 开发者工具,然后打开网络面板,加载您选择的网页,并观察网络面板的最底部。

开发者工具读出的实际大小与传输大小。
所有网页资源的传输大小(即压缩后的大小)与其实际大小的对比图,该图在 Chrome 开发者工具的网络面板中直观呈现。

与上图类似,您应该会看到以下细分数据:

  • 请求数,即为网页加载的资源数。
  • 所有请求的传输大小。这反映了应用于网页任何资源的压缩的有效性。
  • 所有请求的资源大小。此属性反映了网页资源在解压缩的大小。

对 Core Web Vitals 的影响

除非有反映这些改进的指标,否则无法衡量性能改进。Core Web Vitals initiative旨在创建并提高对反映实际用户体验的指标的认知度。这与无法清晰反映用户体验质量的指标(例如简单的网页加载时间)形成对比。

将本指南中概述的优化措施应用于网站上的资源时,对 Core Web Vitals 的影响可能会因优化的资源和涉及的指标而异。不过,在以下情况下,应用这些优化措施可以改善网站的 Core Web Vitals:

  • 经过最小化和压缩的 HTML 资源可以缩短相应 HTML 的加载时间,提高其子资源的可发现性,从而缩短这些子资源的加载时间。这有助于提高网页的 Largest Contentful Paint (LCP)。虽然可以使用 rel="preload" 等资源提示来影响资源的可发现性,但使用过多的资源提示可能会导致带宽争用问题。通过确保导航请求的 HTML 响应经过压缩,预加载扫描器可以尽快发现其中的资源。
  • 使用压缩还可以更快地加载某些 LCP 候选元素。例如,可以通过基于文本的压缩来缩短作为 LCP 候选对象的 SVG 图片的资源加载时长。这与其他图片类型的优化不同,其他图片类型本身是通过其他压缩方法进行压缩的,例如 JPEG 图片使用有损压缩。
  • 此外,文本节点也可以是 LCP 候选对象。本指南中介绍的技术的实现方式取决于您是否在网页上使用网络字体来显示文字。如果您使用的是 Web 字体,则适用 Web 字体优化最佳实践。不过,如果您使用 Web 字体,而是使用不会产生任何资源加载时长的系统字体,那么缩小和压缩 CSS 可缩短此时长,这意味着潜在 LCP 文本节点的渲染可以更快完成。

总结

优化基于文本的素材资源的编码和传输方式是一项基本的性能概念,但它会产生很大的影响。请务必尽一切努力确保符合缩小和压缩条件的资源能够受益于这些优化。

更重要的是,请务必确保这些流程已实现自动化。对于缩小化,请使用打包器对符合条件的资源应用缩小化。确保您的 Web 服务器配置支持压缩,但更重要的是,使用最有效的压缩方式。为了尽可能简化此过程,请使用 CDN 自动为您压缩资源,因为它们不仅可以为您压缩资源,还可以非常快速地完成此操作。

通过将这些基准性能概念融入网站的架构中,您可以确保性能优化工作有一个良好的开端,并确保后续优化可以建立在良好的基准实践之上。