原文preyneyv - 2024.11.02

现代硬件的速度快得令人难以置信。我正在用来写这篇文章的苹果 M1 Max 运行频率为 3.2GHz。这意味着每秒有 32 亿个时钟周期。然而,微软 Teams 打开一个链接却需要 3 秒,我可不信打开一个链接需要耗费 96 亿个时钟周期。显然,这种说法有点过于简单化,但问题依然存在:为什么硬件变得越来越快,而我们使用的应用程序却越来越慢?

“那是因为我们现在要做的事情更多了。”这是一个资本主义晚期享受者的说法。让我来详细解释一下。

电子游戏是现代计算能力的一个绝佳例子。我可以模拟巨大的 3D 环境,配备物理效果和光线追踪,还能与其他州甚至其他国家的朋友实时联机进行游戏,同时在普通消费级硬件上每秒渲染 1.24 亿个像素。

从另一个角度看,人们已经设法让《DOOM》运行在几乎任何可以计算的设备上:计算器、iPod、相机。极低功耗、几乎可以丢弃的设备依然有足够的计算能力来运行一款 1993 年的顶级游戏。这并不令人惊讶,毕竟已经过了三十年,但这也展示了我们已经走了多远。

“Web 很糟糕”

Web 是很酷的。事实上,网络是如此之酷,以至于它在向后兼容性、跨平台性和易用性方面自成一派。Web 还有一种事件驱动模型,让 UI 更容易编写。当然,这些便利也有代价:速度。执行像 JS 这样灵活的语言本质上就很困难,而在对比快速的原生应用程序和缓慢的基于 Web 的应用程序时,这很可能是你首先责怪的原因。解释型、动态类型的语言自然会占用更多内存,运行速度也更慢。

根据你所做的事情,JS 可能确实是罪魁祸首。例如, webpack 需要解析数千个文件,构建 AST,并做一些我完全不懂的复杂 CPU 密集型操作,因此 esbuild(Go)swc(Rust) 比 webpack 快是有道理的。

但在一般的 Web 应用程序中,不,Web 不是你那“放大版 IRC 聊天应用程序”以 5 FPS 运行的原因。前几周 Twitter 上流传的一个例子是 McMaster-Carr 的目录。通过积极的预加载和服务器端渲染,他们能够让网站使用和导航起来感觉异常流畅,尽管使用的是几十年前的技术(ASP.NET 和 jQuery)。随大流的人们此时无比尴尬。

如果你讨厌 React,这似乎是反对 React 和其他“现代” JS 框架的一个有力论据,但这完全是错误的结论。看看 NextFaster源码),这是一份用 Next.js 构建并托管在 Vercel 上的 McMaster 目录的副本,速度同样快,甚至更快。

Web 技术的顶峰可能要数 Figma 了。一个完整的设计工具以 60 FPS 的速度运行,还支持实时多人协作,真的是相当疯狂。公平地说,它并不完全是用 JS 实现的;应用的大部分是用 WebAssembly 和 WebGL 运行的。他们能从原生应用中挤出更多的性能吗?可能吧。但这也意味着要放弃它作为一个“随时可以访问”的网站的便利性。相反,他们选择全力优化,证明了浏览器也完全可以飞速运行。

顺便提一下,特别感谢 V8、SpiderMonkey 和 JavaScriptCore 的开发者们,正是你们的神秘工作让我们其他人能够构建任何东西。

“Electron 很糟糕”

:我用“Electron”来代表 Electron、CEF、WKWebView、Edge WebView2 以及其他任何 web-to-native 封装器。

Electron 使得构建 Web 应用并将其部署为桌面应用成为可能。这种吸引力是毋庸置疑的。现在,你只需使用一套技能,构建一个应用一次,然后就可以为所有架构和操作系统(是的,甚至是 Linux)创建“桌面”应用。

代价是什么?运行 Web 应用唯一可靠的方式就是通过 Web 浏览器,所以 Electron 就……打包了一个 Web 浏览器。会有什么问题呢?¯\_(ツ)_/¯

结果是,问题还真不少。在过去的十年里,应用程序的下载大小超过 500 MB 已经变得可以接受,它们消耗了大量的 RAM 和 CPU,慢慢耗尽了你的电池寿命。而且,尽管消耗了这么多资源,它们的使用体验却并不出色。许多应用程序通过奇怪的滚动和选择行为、外观、导航处理等泄露了它们的非原生性,更不用说切换界面时的缓慢感了。Discord 和 Teams 就是这种 Electron 化的典型例子。它们都有出色的移动端应用,使用起来感觉良好,而桌面端只是重新包装的网站。为什么呢?

把这些问题归咎于 Electron 并不公平。Electron 只是说:“这是一个把你的 Web 应用放进窗口的方式。”

真正的责任在于构建这些应用的公司。构建良好的 Electron 应用完全是可能的——Slack、Obsidian 和 Notion 就是典范。你只需要用心去做。

说到 Electron,就不得不提到 BracketsAtom,以及更为知名的 VS Code。考虑到用 JS 编辑大型文件就像一边朝自己脚开枪一边跑马拉松,VS Code 能运行得这么好,实在令人印象深刻:某种意义上证明了一个观点,但我不确定是哪个观点。

不可否认,VS Code 的成功很大一部分要归功于其周围的插件生态,而这在很大程度上得益于 Web 技术栈的易用性。最近我写了一个(meme)SWC 插件,可以自信地说,原生插件的开发体验远不及 Web 的超快迭代周期。

“原生应用也很糟糕”

这么多对 Web 技术的批评可能会让你以为我很喜欢使用原生应用。大多数原生应用的使用体验确实很棒(例如 PosticoZed),我经常发现自己只要有可能就会使用它们。

自从几个月前切换到 Zed 后,我觉得自己很难再回到 VS Code。所有操作都 瞬间 完成。你可能觉得 VS Code 已经“够快”了,但这就像音速和光速的区别。你几乎能感觉到它,但确实会产生巨大的差异。Zed 是怎么做到的呢?他们从零开始编写了自己的 GPU 框架,并用 Rust 编写了整个编辑器。当你真正使用现代硬件时,它 真的 很快。谁能想到呢?

我很想进一步尝试 React Native 的桌面端版本。RN 的类似 DOM 的渲染模型让我这个 Web 开发者感到很亲切,我认为它在良好的开发体验和良好的性能之间找到了平衡,尤其是有了 新架构。目前我还不清楚为什么 React Native 在桌面端不太常见,因为从理论上看,它似乎是一个理想的平衡(可能只是因为缺乏官方支持)。

不幸的是,原生应用的世界也不全是美好的。Adobe 产品以频繁崩溃而闻名。Windows 11 的搜索菜单差得可笑。macOS 的活动监视器需要 5 秒钟才能显示正在运行的程序列表。

那我们注定没救了吗?

显然,这些问题并不局限于某种特定的编程语言、操作系统或行业。这是一种更广泛的趋势:快速构建,质量却越来越差。

公共资源的悲剧

近年来情况尤其糟糕,因为现代计算机的性能远远超过了普通人所需的水平。如果你在桌面浏览器上滚动 YouTube Shorts,它会逐渐泄漏内存(超过 2 GB!),直到最终达到资源限制。这在以前是不可能的,因为那时的电脑总共只有 2 GB 内存。现代机器看似充足的计算资源,已经成为构建劣质产品的借口。

“够好”的心理战

显然,我非常在乎使用体验是否良好,但通过与不同人的交谈,我意识到这并不像你想象的那么普遍。大多数人对右键菜单需要 500 毫秒才出现感到“无所谓”,他们也会忽略调整窗口大小时发生的那种卡顿重绘。这可能是从过去等 15 秒加载一张图片的时代遗留下来的习惯,或者是对糟糕用户体验的无奈之举。我们可以做得更好。我们有这个技术能力。

“快速上线”文化

构建产品,快速构建产品。这篇文章并不是为了批判新想法的快速迭代,但把性能当作技术债务和完全忽略性能是有天壤之别的。在我们日常使用的许多产品中,感觉性能甚至都没有被考虑过,仿佛他们在等硬件赶上。这种方法在你做前沿技术时可能是合理的,但如果你的工作只是往屏幕上显示文本,我很难赞同这种做法。

追求性能的“表演”

读完这篇文章,你可能会推测我的建议是将一切都优化到 CPU 指令级别。虽然这本身也很令人钦佩,但对于大多数软件来说,这是完全不现实的(除非你是制作《过山车大亨》的 Chris Sawyer)。这篇文章也不是为了单纯追求性能而优化性能。它只是意识到,现代大规模软件似乎很少关心使用体验,因为你无论如何都会使用它。这是我不想看到的未来。

如果你是一名软件开发人员,我鼓励你以精确和高质量来构建软件。关注那些毫秒级的细节。珍惜你喜欢使用的那些产品。为你的技术感到自豪。

不要再用更多的资源去做更少的事情了。