HTTP/2 一直是我关注的领域之一。 实际上,仅仅在去年我就写了几篇关于它的文章。 在其中一篇文章中,我做出了这个未经证实的断言
如果用户使用 HTTP/2: 您将提供更多更小的资源。 您将避免使用诸如图像雪碧图、内联 CSS 和脚本以及连接的样式表和脚本之类的东西。
我并不是唯一一个这样说的人,不过,公平地说,Rachel 在她的文章中用一些注意事项限定了她的断言。 公平地说,从理论上讲,这并非糟糕的建议。 HTTP/2 的多路复用功能使我们能够避免捆绑,而不会遭受头部阻塞的负面影响(我们在 HTTP/1 环境中对此非常熟悉)。 解开一些这些特定于 HTTP/1 的优化也可以使开发变得更容易。 在网络开发似乎比以往任何时候都更复杂的时候,谁不希望简单一些呢?
与任何在理论上看起来很简单的东西一样,将某些东西付诸实践可能是一件很麻烦的事情。 随着时间的推移,我收到了来自细心读者关于此主题的宝贵反馈,这让我重新思考了我关于哪些实践最适合 HTTP/2 环境的未经证实的断言。
反对打包的理由
关于为 HTTP/2 解包资源的争论主要围绕缓存展开。 前提是,如果您提供更多(更小)的资源而不是一个巨大的包,则对于具有已填充缓存的回头用户的缓存效率会更好。 讲得通。 如果一个小的资源发生更改并且该资源的缓存条目失效,则在下次访问时它将再次下载。 但是,如果只有包的一小部分发生更改,则必须重新下载整个巨大的包。 这并不是最佳选择。
为什么解包可能不是最佳选择
有时解开包是有意义的。 例如,代码分割 促进了更小、数量更多的资源,这些资源仅针对网站/应用程序的特定部分加载。 这是非常有意义的。 而不是预先加载网站的整个 JS 包,您可以将其分成更小的块并按需加载。 这可以保持各个页面的有效负载较低。 它还最大限度地减少了解析时间。 这是好事,因为过度的解析会导致页面绘制并变得可交互但尚未完全加载时出现卡顿和不愉快的体验。
但是,当我们将资源分割得太细时,有时会错过一个缺点:压缩率。 一般来说,较小的资源压缩效果不如较大的资源。 实际上,如果某些资源太小,则某些服务器配置将完全避免压缩它们,因为这样做没有实际收益。 让我们看看一些流行的 JavaScript 库的压缩效果如何
文件名 | 未压缩大小 | Gzip(比率 %) | Brotli(比率 %) |
jquery-ui-1.12.1.min.js | 247.72 KB | 66.47 KB (26.83%) | 55.8 KB (22.53%) |
angular-1.6.4.min.js | 163.21 KB | 57.13 KB (35%) | 49.99 KB (30.63%) |
react-0.14.3.min.js | 118.44 KB | 30.62 KB (25.85%) | 25.1 KB (21.19%) |
jquery-3.2.1.min.js | 84.63 KB | 29.49 KB (34.85%) | 26.63 KB (31.45%) |
vue-2.3.3.min.js | 77.16 KB | 28.18 KB (36.52%) | |
zepto-1.2.0.min.js | 25.77 KB | 9.57 KB (37.14%) | |
preact-8.1.0.min.js | 7.92 KB | 3.31 KB (41.79%) | 3.01 KB (38.01%) |
rlite-2.0.1.min.js | 1.07 KB | 0.59 KB (55.14%) | 0.5 KB (46.73%) |
当然,这个比较表有点过头了,但它说明了一个关键点:作为经验法则,大型文件往往比小型文件产生更高的压缩率。 当您将大型包拆分为微小的块时,您将无法从压缩中获得那么多的好处。
当然,性能不仅仅是资源大小。 在 JavaScript 的情况下,我们可能希望倾向于更小的页面/模板特定文件,因为特定页面的初始加载在文件大小和解析时间方面都将更加流畅。 即使这些较小的资源本身压缩效果不佳。 就我个人而言,如果我正在构建一个应用程序,我会倾向于这样做。 在传统的、同步的“网站”式体验中,我不太倾向于追求代码分割。
然而,需要考虑的不仅仅是 JavaScript。 以 SVG 雪碧图为例。 在这些资源方面,打包似乎更有意义。 特别是对于大型雪碧图集。 我对一个 非常大的包含 223 个图标的图标集 进行了一个基本的测试。 在一个测试中,我提供了一个雪碧图版本的图标集。 在另一个测试中,我将每个图标作为单个资源提供。 在使用 SVG 雪碧图的测试中,图标集的总大小仅代表不到 10 KB 的压缩数据。 在使用解包资源的测试中,相同图标集的总大小为115 KB 的压缩数据。 即使有多路复用,在任何给定的连接上,115 KB 也不可能比 10 KB 加载得更快。 个别图标的压缩程度不足以弥补差异。技术旁注:在这两个测试中,SVG 图像都经过了 SVGO 优化。
旁注:一位敏锐的评论者 指出,Firefox 开发人员工具显示,在未使用雪碧图的测试中,传输了大约 38 KB 的数据。 这可能会影响您的优化方式。 只需要记住这一点。
不支持 HTTP/2 的浏览器
是的,这是个问题。 Opera Mini 特别是在这方面似乎是一个例外,并且根据您的用户,这可能不是一个可以忽略的用户群体。 虽然全球约 80% 的人使用可以支持 HTTP/2 的浏览器上网,但在世界的一些角落,这个数字有所下降。 例如,在印度,不到 50% 的用户使用可以与 HTTP/2 服务器通信的浏览器(无论如何,根据 caniuse 的说法)。 至少目前是这样的情况,并且支持趋势正在上升,但浏览器对该协议的普遍支持还有很长的路要走。
当用户使用不支持它的浏览器与 HTTP/2 服务器通信时会发生什么? 服务器将回退到 HTTP/1。 这意味着您将回到旧的性能优化范式。 所以再次,做好功课。 检查您的分析并查看您的用户来自哪里。 更好的是,利用 caniuse.com 的功能来分析您的分析并查看您的受众支持什么。
现实检验
是否有任何理智的开发者会将其前端代码设计为加载 223 个单独的 SVG 图像? 我希望不会,但是 没有什么能再让我感到惊讶了。 在除最复杂和功能最丰富的应用程序之外,您很难找到如此多的图标。 但是,对于您来说,将这些图标合并到雪碧图中并预先加载它以获得后续页面导航中更快渲染的好处可能更有意义。
这让我得出了一个不可避免的结论:在 Web 性能学科的各个角落,没有简单的答案,除了“做你的研究”。 依靠分析来决定打包是否对您的 HTTP/2 驱动网站有利。 您是否有许多只访问一两个页面然后离开的用户? 也许不要浪费时间打包东西。 您的用户是否在您的网站中深度导航并花费大量时间? 也许打包。
这一点对我来说很清楚:如果您将您的 HTTP/1 优化网站迁移到 HTTP/2 主机并且没有更改客户端架构中的任何内容,那将不会有什么大问题。 因此,不要相信一些编写博客文章的 Web 开发人员(例如,我)的笼统陈述。 弄清楚您的用户行为、什么优化最适合您的情况,并相应地调整您的代码。 祝你好运!
我在 Firefox Nightly 开发人员工具中检查过。 雪碧图的大小为“传输了 9.55 KB”,而 223 个单独 SVG 的大小为 36.53 KB。 这仍然增加了 3.8 倍。 但是,这是假设页面上实际上使用了所有图标。
223 / 3.8 = ~60。 因此,如果页面使用的图标少于 60 个,则如果单独加载它们,它将使用更少的 KB。 我认为 60 个对于任何给定的页面都应该足够了。
非常有趣。Chrome 显示的内容更多。Chrome 似乎发送了更多的头部信息,但这并不能解释额外的文件大小。
你提出了一个很好的反驳观点。我想我试图将某些内容与我关于压缩率的观点联系起来。如果你在多个页面上分散了 60 个图标,但在任何一个页面上最多只使用几个,那么按照你所说的去做肯定是有利的。
但也可以认为,如果你提前加载这些图像,后续页面的加载速度可能会加快,但对此存在实际上的利弊。
感谢你的参与。 :)
尽管如此,使用 HTTP2 推送在不同浏览器和操作系统中存在很多 bug,因此弊大于利。
Victor - 你能详细说明你在使用 HTTP/2 推送时遇到的缺点/错误吗?我个人使用不多,很感兴趣了解更多关于这方面的信息,因为我以前从未听说过。
Jake Archibald 有一篇很棒的文章,展示了 HTTP2 推送的一些问题。
HTTP/2 服务器推送与本主题有点关系,但并非完全无关。毕竟,内联可以被理解为一种打包形式。服务器推送可以解决内联资源的缓存相关缺点,同时提供类似的性能优势。
但问题是,正如你所说,推送目前还有一些 bug。Jake Archibald 写了一篇优秀的文章,概述了跨浏览器的服务器推送异常情况。
也就是说,我使用基于 cookie 的机制在后端尝试消除冗余推送方面取得了不错的成功。这对我来说似乎效果很好,但在所有情况下都远非最佳。
感谢阅读。 :)
是的,你是对的,这完全取决于读者在即将到来的网站开发过程中实施过程的受众。这就是为什么即使是前端开发人员也值得深入研究 Analytics 中的**受众**部分,以回答这些问题,即 HTTP/2 是否普遍适用于即将推出的网站的受众。
此致,
Mic
我认为没有人真正说“完全不要打包你的文件”,与 HTTP/2 中的打包相关的黑暗模式更多地围绕加载特定页面上未使用的代码。如果你的模板/页面使用了 5 个模块,你仍然可以将它们打包在一起,只是不要在一个使用 5 个模块的页面上打包 10 个模块。
同样,你也可以为页面定制精灵图;如果你只使用几个图标,就没有必要使用一个巨大的精灵图文件。你不需要将它们拆分成一堆文件,但你也不必使用一个巨大的精灵图来处理(如果可以的话,采取折中方案)。有了更好的头部压缩和多路复用,这些类型的构建修改将在 HTTP/2 中获得更大的收益。
我的理解是,在 HTTP/2 下,用户等待一组图像的时间由其中最大的单个图像决定。
如果是这种情况,并且我的 svg 图像中最大的图像小于以前包含该组图像的精灵图,那么如果单独提供这些图像而不是作为精灵图,则用户将获得净收益。
再说一遍,我可能遗漏了一些东西。多路复用下可能存在并行下载文件的最大数量。