JavaScript Hydration 是一种解决方法,而不是解决方案

2,478 阅读5分钟

在 Web 开发中,Hydration是一种向服务器呈现的 HTML 添加交互性的技术。这是一种技术,客户端 JavaScript 通过将事件处理程序附加到 HTML 元素,将静态 HTML 网页转换为动态网页。

但是,将事件处理程序附加到文档对象模型 (DOM) 并不是水化过程中最具挑战性或成本最高的部分。

在本文中,我将解释为什么我认为补水是开销。这不是解决方案;这是一种消耗内存并减慢启动速度的技巧,尤其是在移动设备上。为了本文的目的,让我们将开销定义为可以避免但仍会导致相同最终结果的工作。

深入研究水合作用

hydration 的难点在于知道我们需要哪些事件处理程序以及它们需要附加到哪里。

  • WHAT:事件处理程序是一个包含事件行为的闭包。如果用户触发此事件,则应该发生这种情况。
  • WHERE:需要附加 WHAT 的 DOM 元素的位置(包括事件类型)

增加的复杂性是 WHAT 是一个关闭APP_STATEFW_STATE的闭包:

  • APP_STATE:应用程序的状态。APP_STATE是大多数人认为的状态。如果没有APP_STATE,您的应用程序将无法向用户显示任何动态。
  • FW_STATE:框架的内部状态。如果没有FW_STATE,框架不知道要更新哪些 DOM 节点或框架应该何时更新它们。示例是组件树和对渲染函数的引用。

那么我们如何恢复 WHAT 和 WHERE?通过下载和执行 HTML 中呈现的组件。这是昂贵的部分。

换句话说,水合是一种通过在浏览器中急切执行应用程序代码来恢复APP_STATEFW_STATE的技巧,包括:

  • 下载组件代码。
  • 执行组件代码。
  • 恢复 WHAT(APP_STATEFW_STATE)和 WHERE 以获取事件处理程序关闭。
  • 将 WHAT(事件处理程序闭包)附加到 WHERE(DOM 元素)。

我们将前三个步骤称为恢复阶段。

恢复是框架试图重建应用程序的时候。重建成本很高,因为它需要下载和执行应用程序代码。

恢复与水合页面的复杂性成正比,在移动设备上很容易花费 10 秒。由于恢复是昂贵的部分,大多数应用程序的启动性能都不理想,尤其是在移动设备上。

恢复也是开销:它重建服务器已经作为服务器端渲染 (SSR) 或静态站点生成 (SSG) 的一部分收集的信息。不是将信息发送给客户端,而是丢弃了信息。因此,客户端必须执行昂贵的恢复来重建服务器已有的内容。如果只有服务器将信息序列化并将其与 HTML 一起发送给客户端,就可以避免恢复。序列化的信息将使客户端免于急切地下载和执行 HTML 中的所有组件。

换句话说,在客户端上重新执行服务器已经作为 SSR/SSG 的一部分执行的代码是使水合成为纯粹开销的原因。

可恢复性:水化的无开销替代方案

为了消除开销,框架不仅要避免恢复,还要避免上面的第四步:将 WHAT 附加到 WHERE。

为了避免这种成本,您需要三件事:

  • 作为 HTML 的一部分序列化的所有必需信息,包括 WHAT、WHERE、APP_STATE和FW_STATE 
  • 一个全局事件处理程序,它依赖于事件冒泡来拦截所有事件,这样我们就不会被迫在特定的 DOM 元素上单独注册所有事件。
  • 一个可以延迟恢复事件处理程序(WHAT)的工厂函数。

上述设置是可恢复的,因为它可以在服务器停止的地方恢复执行,而无需重做服务器已经完成的任何工作。通过懒惰地创建 WHAT 作为对用户事件的响应,我们可以避免在 hydration 中进行所有不必要的工作。所有这些都意味着没有开销。

内存使用情况

DOM 元素在元素的生命周期内保留事件处理程序。Hydration 急切地创建所有侦听器,因此它需要在启动时分配内存。

另一方面,可恢复框架在事件触发之前不会创建事件处理程序。因此,它们将比水合消耗更少的内存。此外,事件处理程序在执行后被释放,返回内存。

在某种程度上,释放记忆与水合作用相反。就好像框架懒洋洋地对特定的 WHAT 进行水合,执行它然后对其进行脱水。处理程序的第一次和第 n 次执行之间没有太大区别。

结论

简而言之,水合作用是开销,因为它重复工作。服务器建立 WHERE 和 WHAT(APP_STATEFW_STATE),但信息被丢弃而不是为客户端序列化。客户端然后收到没有足够信息来重建应用程序的 HTML。缺乏信息迫使客户端急切地下载应用程序并执行它以恢复 WHERE 和 WHAT。

另一种方法是可恢复性。可恢复性侧重于将所有信息(WHERE 和 WHAT)从服务器传输到客户端。只有用户交互会强制客户端下载代码来处理该特定交互。客户端没有从服务器复制任何工作;因此,没有开销。