打造世界上最快的网站以及其他错误

2025-05-28

打造世界上最快的网站以及其他错误

这是一个关于很多事情的故事:

  • 将财富 20 强网站限制在 20kB 以内
  • 深入研究网站速度,我们会看到长着尖牙的鱼
  • React 阻碍了我为用户提供真实服务的目标
  • 竭尽全力做正确的事情
  • 最后,我鼓励你尝试一些代码。

情况:令人沮丧的典型

我负责 Kroger 区域连锁店的电商网站建设,这些网站大部分都共享一个代码库。你大概能猜到前端堆栈:React、Redux,以及它们常见的 JavaScript 泛滥问题

WebPageTest 活动图显示一片浓密的黄色区域代表 JavaScript 执行,下方大部分红色区域表示无法进行交互。最糟糕的部分?X 轴超过了 46 秒。

事实:

具体来说, React SSR 就是那些看起来速度更快但外表可能具有欺骗性的变化之一。回想起来,我很惊讶开发人员竟然认为 SSR + rehydration 是一种改进

通过运行两次,让您的代码更快!

React SSR 的工作原理

背景故事:开发人员被放射性 WebPageTest 咬伤

我曾经建议其他开发人员不要再写速度慢的代码。1例如……

  • “请减少<div>s,它们会使我们的 DOM 变得又大又慢。”

  • “请避免使用类似 CSS .Component > * + *,它与我们的大 DOM 结合会导致明显的滞后。”

  • “请不要把 React 用于所有事情,它会限制我们的速度。”(特别是如果它渲染具有复杂样式的大型 DOM……)

没人听。不过说实话,他们为什么要听呢?

这种情况持续了下来,而且很酷/很酷/令人沮丧/很酷。但是,新的设计系统对 Tailwind 造成了足够的影响,导致桌面首次绘制时间缩短了 0.5 秒,这足以与专门的 Web 性能团队进行协商。

一切进展顺利,直到事情变得糟糕。瞧,这就是速度优化团队的行业标准生活:

  1. 通过改进构建配置、删除重复库和删除死代码等无争议的改变取得成功
  2. 审核其他团队的代码并提出改进建议
  3. 上述建议之后,我们自己进行改进,但始终未能摆脱积压
  4. 尝试通过 bundle size 监控、PR 中的 Lighthouse 检查以及其他新的流程层来实现改进
  5. 听到人们因为必须遵守上述层层程序而发出哀号和咬牙切齿的声音
  6. 意识到我们需要解释为什么我们惹恼了其他人,否则我们就会被认为对利润产生负面影响

问题是,WebPageTest 对我们的速度皱眉并没有转化为糟糕的移动流量 - 事实上,大多数用户都在使用 iPhone。2商业角度来看,当图表向上和向右移动时,谁会在乎网站是否可以更快?

为了证明我们没有浪费大家的时间,我们使用了WPO Stats和内部数据来计算,每 kB 的客户端 JavaScript 每年花费我们约 100,000 美元,而直到可交互时间到来之前的每一毫秒至少花费 40,000 美元。3

但证明速度=金钱只会让我们从愤怒进入对性能的悲痛的讨价还价阶段:囤积改进以供日后使用、在截止日期后修复大量回归的空洞承诺,以及以“开发人员体验”为诉求的抗议数字。

表现悲伤的五个阶段
拒绝 速度够快了。你看过那些 M1 基准测试了吧?
愤怒 你的意思是我也得关心这个!?我们刚刚才关心完可访问性!
讨价还价 我保证,如果您让我们跳过捆绑检查,我们最终将合并到三个工具提示库中
悲伤 当我尝试看看是否有效时,我应该意识到我走上了一条黑暗的道路npm install *
验收 我喜欢我的慢速网站。

仅仅证明速度很重要还不够:我们还得在情感上说服大家。天哪,要让所有人知道,如果我们的网站速度快了,会有多好。

因此,我决定创建一个重复使用我们的 API 的演示站点,但速度尽可能快。

剧透:我自己都没想到,我成功了。然后事情就变得很奇怪了。不过在讲这个故事之前,我得先讲这个故事……

目标:速度有多快?



HTTP/1.1 204 No Content
Cache-Control: max-age=999999999,immutable


Enter fullscreen mode Exit fullscreen mode

这是最快的网页。你可能不喜欢,但这就是巅峰性能的体现。

这看起来似乎没什么用——当然,一个有用的页面比什么都没有还慢!——但任何添加到前端的东西都只会减慢它的速度。某些东西越是偏离网络的自然速度,就越需要付出更多努力来恢复它。

话虽如此,还是需要留出一些余地,否则我会浪费时间去微调每一个细节。你确实想知道你的内容、设计或开发选择何时开始影响你的用户。对于所有新增的功能,你都应该权衡其利弊。这就是性能预算存在的原因

但要确定我的预算,我首先需要某种更高层次的目标。

某种更高层次的目标

🎯 速度如此之快,以至于在客户使用的最差的设备和网络上也很有趣。

目标设备:当地 Kroger 超市畅销的手机
辣椒的波布拉诺 VLE5
35 美元(促销价 15 美元)
规格:1 GB RAM、8 GB 总磁盘存储空间和 1.1 GHz 处理器。
目标连接:“慢速 3G”
400kbps带宽
400ms 往返时间延迟
当时,Google 建议测试什么,以及 WebPageTest 的“简单”配置和 Lighthouse 使用了什么

不幸的是,网络连接比“慢速 3G”预设的还要差,Kroger 超市内部的蜂窝数据就是一个例子。大型仓储式商店的架构就像法拉第笼一样,丢失大量数据包,从而消耗带宽和延迟。

最终,我选择了“慢速 3G”,因为它能够平衡美国大部分地区较快的网速和商店内的信号干扰。我请 Alex Russell 核实这篇文章时,他也提到“我们在农村地区仍然能看到类似的延迟”。

(这些设备和连接目标是高度特定于这个项目的:我带着网络分析仪走进商店,询问前台哪种手机最受欢迎,等等。我不会将它们视为“正常”基线。)

(等等,如果连接不稳定,是不是意味着您应该使用 Service Worker?)

是的,当网络状况很差时,您必须将其视为可选项,这是服务人员的工作。

撰写有关特殊 SW 酱料的文章(预告:离线流、导航预加载缓存摘要和关键 CSS 的前沿),但即使是最好的服务工作者对于网站的首次加载也是无关紧要的。


虽然我知道我想要什么规格,但我不知道这对我的预算意味着什么。幸运的是,其他人知道。

谷歌关于提高移动设备速度的建议

谷歌似乎知道如何解决网络性能问题,但他们从未正式认可特定的预算,因为它不可能是一刀切的。

虽然谷歌对具体预算讳莫如深,但他们的前首席性能主管亚历克斯·拉塞尔却并非如此。他撰写了一些重要信息,表明网络需要加速到何种程度才能保持相关性,而这篇文章正是我需要的:

综合起来,在理想条件下,我们对关键路径资源(CSS、JS、HTML 和数据)的粗略预算为:

  • 对于没有太多 JS 的网站,170KB
  • 对于使用 JS 框架构建的网站,大小为 130KB

你能负担得起吗?现实世界的性能预算

Alex 后来更新了这些数字,但这些是我当时使用的数字。如果您有兴趣,请阅读这两个数字 - Alex 解释了我提到的那些比平常更糟糕的网络,展示了他在数字背后的工作,并且毫不掩饰地说明了究竟是什么减慢了网页速度。)

不幸的是,Alex 提到的硬件频率是 2GHz,而 Poblano 的频率是 1.1GHz。这意味着预算应该会降低到 100kB 左右,但我无法接受。为什么?

围绕分析进行工程设计

一如既往,第三方会毁掉一切。您可以看到2022 年网站的跨源字节情况,其中还不包括像 Dynatrace 这样的同源第三方。

挤进汽车的小丑剖面图。

摘自《小丑车的物理学》·《人车志》

我无法公布确切的数字,但当时的情况也好不到哪里去。除非发现反千字节,否则我得弄清楚哪些第三方必须被淘汰。当然,他们中的大多数都赚了钱,但我要证明,放弃他们也能赚到钱。

经过一番深思熟虑,我最终还是放弃了大约 138kB 的第三方 JS,我觉得公司肯定不会允许我离开它。就像往罐子里装满石头、鹅卵石和沙子的故事一样,我觉得绕过这些巨石进行开发比一开始就建一个“足够快”的网站,然后把它搞砸要容易得多。

经过一些绝望的延迟加载实验后,我发现我的代码不能超过 20kB(压缩后),以听取 Alex 的建议。

好的,20kB。接下来怎么办?

20KB 不算多。react+react-dom几乎是它的两倍。一个显而易见的替代方案是4KB 的 Preact,但它对组件代码或 Redux 灾难毫无帮助——而且我还需要 HTML 和 CSS!我不得不在这些显而易见的选择之外寻找其他选择。

一个网站真正需要什么如果我回答了这个问题,其他一切都可以忽略不计了。

那么,即使你尝试过,网站也不能省略什么呢?

可以只用 HTML 创建一个真正的网站——在 CSS 和 JS 出现之前,人们一直都是这样做的。

也许如果我在 HTML 中添加足够的CSS 就会看起来不错...并且如果我还有剩余空间,那么可以为从复杂交互中受益最多的部分添加一些激光聚焦的 JavaScript。

(是的,我看到你穿着Svelte.js衬衫。我将在下一篇文章中讨论它。)

如果你使用非常糟糕的 User-Agent访问亚马逊,它基本上会提供我刚才描述的内容

亚马逊展示了什么Opera/9.80 (J2ME/MIDP; Opera Mini/5.1.21214/28.2725; U; ru) Presto/2.8.119 Version/11.10

通过 Opera Mini 浏览 Amazon.com:屏幕上显示一个产品,底部显示导航,网站标题精简为徽标、交易/购物车/列表链接和搜索栏。


这是保真度最低的亚马逊版本,通过skin=noskincookie 来显示。

这是一个炫酷的 Web 1.0 风格的产品页面,展示了两个梅森罐。Times New Roman 字体印在空白背景上,唯一的格式就是图片居中、添加按钮和一些水平线。

看来我的计划可行,而且显然利润丰厚,亚马逊也打算这么做。看来不错,值得一试。

但每个人都知道经典的页面导航很慢!

你确定吗?我之前也这么想……

  • 如果您内联 CSS 并高效生成 HTML,那么与网络往返相比,它们的开销可以忽略不计。
  • 单页应用仍然需要 JSON 数据进行渲染,对吧?即使你将 JSON 数据内联到初始响应中,JSON→JavaScript→HTML 也不可能比直接跳到 HTML 部分更快。
  • 在服务器上连接字符串不应该成为一个巨大的瓶颈。如果是的话,React SSR 如何证明将这些字符串两次连接到 HTML 和 Hydration 数据中是合理的?

但别轻信我的话——下次我们再看看结果如何。具体来说,我首先需要解决一个问题:如何在所有慢速数据源完成之前发送页面?


  1. 我仍然要求其他开发人员停止编写缓慢的代码,我以前也这样做过。↩ 

  2. 这不算内幕消息。任何拥有类似前端载荷的美国网站都会告诉你同样的事情 。↩

  3. 这些数字是非常宽松、保守的估计。它们也不再准确——现在的数字要高得多——但它们仍然可以作为最低限度的参考 。↩

文章来源:https://dev.to/tigt/making-the-worlds-fastest-website-and-other-mistakes-56na
PREV
路由:我不够聪明,无法实现 SPA
NEXT
保持代码简单