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

除了消除不必要的资源下载之外,您还可以通过优化和压缩剩余资源来最大限度地缩减总下载大小,从而提高网页加载速度。

数据压缩基础知识

设置好网站以避免下载任何未使用的资源后,下一步就是压缩浏览器必须下载的所有剩余符合条件的资源。根据资源类型(文本、图片、字体等),有许多不同的技术可供选择:可在 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 规则或进行其他数十种特定于内容的优化。因此,预处理、缩减大小和其他上下文感知优化非常重要。

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

简而言之,作为优化资源效率的第一步,请构建不同内容类型的清单,并考虑可以应用哪些特定于内容的优化来缩减其大小。然后,在确定这些优化措施后,将它们添加到构建和发布步骤中,以自动执行这些优化,从而确保每次发布到生产环境的新版本都始终如一地应用这些优化。

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

缩减文本资源大小的下一步是对其应用压缩算法。这种方法更进一步,在将基于文本的载荷发送给用户之前,会主动搜索其中的可重复模式,并在载荷到达用户浏览器后对其进行解压缩。这样可以进一步大幅减少这些资源,从而缩短下载时间。

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

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

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

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

文件 算法 未经压缩的大小 压缩后的大小 压缩比
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 开发者工具,打开网络面板,加载您选择的网页,然后观察网络面板的最底部。

DevTools 读出的实际大小与传输大小。
所有页面资源的传输大小(即压缩后的大小)与其在 Chrome 开发者工具的“网络”面板中显示的实际大小的对比图。

如上图所示,您应该会看到以下各项的细分数据:

  • 请求数量,即为网页加载的资源数量。
  • 所有请求的传输大小。这反映了对网页的任何资源应用压缩的效果。
  • 所有请求的资源大小。这反映了解压缩后网页资源的大小。

对 Core Web Vitals 的影响

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

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

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

总结

如何优化基于文本的资源的编码和传输是一个基本的性能概念,但它会产生重大影响。请务必尽一切努力,确保符合缩减大小和压缩条件的资源能够从这些优化中受益。

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

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