渐进增强(和优雅降级)
我在波士顿开车已经大约十五年了。如果你不了解波士顿,让我告诉你:马萨诸塞州拥有一些世界上最激进的司机(和行人!)我学会了实践有时被称为“防御性驾驶”的东西:假设当你在交叉路口有路权时,有人即将在你面前突然转向,准备好随时有行人过马路,并相应地驾驶。
“渐进增强”是网页设计的“防御性驾驶”。或者实际上,那是“优雅降级”,尽管它们是同一枚硬币的两个面,或者说是同一个过程,只是方向不同。
在这种情况下,渐进增强 意味着从一个简单的 HTML 网站或应用程序开始,该网站或应用程序适用于访问你的页面的任何用户,并逐渐使用其他功能层对其进行增强:用于样式的 CSS、用于交互性的 JavaScript、用于 Rust 驱动的交互性的 WebAssembly;如果可用,则根据需要使用特定的 Web API 以获得更丰富的体验。
优雅降级 意味着当增强堆栈的某些部分不可用时,能够优雅地处理故障。以下是一些你的用户在你的应用程序中可能遇到的故障来源:
- 他们的浏览器不支持 WebAssembly,因为它需要更新。
- 他们的浏览器无法支持 WebAssembly,因为浏览器更新仅限于较新的操作系统版本,而这些版本无法在其设备上安装。(说你呢,Apple。)
- 出于安全或隐私原因,他们已关闭 WASM。
- 出于安全或隐私原因,他们已关闭 JavaScript。
- 他们的设备不支持 JavaScript(例如,某些辅助功能设备仅支持 HTML 浏览)
- 因为他们走到室外并在 WASM 完成加载之前丢失了 WiFi,所以 JavaScript(或 WASM)从未到达他们的设备。
- 他们在加载初始页面后踏上地铁车厢,后续导航无法加载数据。
- ... 等等。
如果其中之一成立,你的应用程序还有多少可以正常工作?两个?三个?
如果答案类似于“95%... 好吧,然后是 90%... 好吧,然后是 75%”,那就是优雅降级。如果答案是“除非一切正常,否则我的应用程序会显示一个空白屏幕”,那就是... 快速计划外拆卸。
优雅降级对于 WASM 应用程序尤其重要, 因为 WASM 是在浏览器中运行的四种语言(HTML、CSS、JS、WASM)中最新的、最不可能被支持的。
幸运的是,我们有一些工具可以提供帮助。
防御性设计
有一些实践可以帮助你的应用程序更优雅地降级:
- 服务器端渲染。 没有 SSR,你的应用程序在没有加载 JS 和 WASM 的情况下根本无法工作。在某些情况下,这可能是合适的(想想在登录后受保护的内部应用程序),但在其他情况下,它只是坏了。
- 原生 HTML 元素。 使用可以完成你想要的事情的 HTML 元素,而无需额外的代码:
<a>
用于导航(包括页面内的哈希值)、<details>
用于手风琴、<form>
用于在 URL 中保存信息等。 - URL 驱动的状态。 你的全局状态越多存储在 URL 中(作为路由参数或查询字符串的一部分),在服务器端渲染期间可以生成的页面就越多,并且可以通过
<a>
或<form>
更新,这意味着不仅导航而且状态更改都可以在没有 JS/WASM 的情况下工作。 SsrMode::PartiallyBlocked
或SsrMode::InOrder
。 乱序流式传输需要少量内联 JS,但如果 1) 连接在响应中途断开或 2) 客户端设备不支持 JS,则可能会失败。异步流式传输将提供一个完整的 HTML 页面,但只有在所有资源加载完成后才会提供。顺序流式传输会更快地开始显示页面的各个部分,按自上而下的顺序。“部分阻塞”SSR 通过在服务器上替换从阻塞资源读取的<Suspense/>
片段来构建乱序流式传输。这会略微增加初始响应时间(因为O(n)
字符串替换工作),以换取更完整的初始 HTML 响应。对于“更重要”和“不太重要”内容之间有明显区别的情况,例如博客文章与评论,或产品信息与评论,这是一个不错的选择。如果你选择阻塞所有内容,则实际上你已经重新创建了异步渲染。- 依赖
<form>
。 最近<form>
有点复兴,这并不奇怪。<form>
以易于增强的方式管理复杂的POST
或GET
请求的能力使其成为优雅降级的强大工具。例如,<Form/>
章节 中的示例在没有 JS/WASM 的情况下也能很好地工作:因为它使用<form method="GET">
在 URL 中保存状态,所以它通过发出普通的 HTTP 请求来使用纯 HTML,然后逐步增强以使用客户端导航代替。
框架还有一个我们尚未看到的功能,它建立在表单的这一特性之上,用于构建强大的应用程序:<ActionForm/>
。