由Miško Hevery。
原始:https://www.builder.io/blog/resumability-vs-hydration
简历是水合的更快替代品。乍一看,似乎是可重复的,水合是相同的。毕竟,两者都会为您的页面带来互动性。将水合定义为“仅制作页面交互式”是如此广泛,因为它不可用,因为它包括非服务器渲染的应用程序。
要考虑水合的东西,该页面需要在没有服务器步骤的情况下具有预渲染服务器步骤(SSR或SSG)。因此,没有水合。 (这是一个重要的区别,因为水合和客户渲染在大多数情况下是同一件事。)
因此,如果水合和恢复性都做同样的事情,那有什么区别?我认为理解区别的最佳方法是创建一个小示例,显示水合作用,并注意代码执行的何处(服务器vs client)和何时(互动之后的vs之前)。
。在此示例中,我们将选择三个框架,因为它们在水合 /可重复性频谱上展示了不同的方法:< / p>
- React:一个流行的框架,在水合和交互性上执行组件。 (游乐场)
- solidjs:一个细粒的反应框架,仅在水合(不进行交互)上执行组件。(游乐场)
- Qwik:一个细粒的反应框架,不进行水合,因此不会在水合上执行代码。 (游乐场)
客户端渲染
在我们跳入水合作用和可重复性之前,请审查客户端渲染(CSR)的工作方式。为了真正欣赏这些好处,重要的是要有一个具有吊装状态的组件层次结构。
import * as React from 'react';
import { useState } from 'react';
import './style.css';
export default function Counter() {
console.log('Render: <Counter/>');
const [count, setCount] = useState(0);
return (
<div>
<Display count={count} />
<Incrementor setCount={setCount} count={count} />
</div>
);
}
function Display(props: { count: number }) {
console.log('Render: <Display/>');
return <div>Current count: {props.count}</div>;
}
function Incrementor(props: {
count: number;
setCount: (count: number) => void;
}) {
console.log('Render: <Incrementor/>');
return (
<button
onClick={() => {
console.log('Interaction: +1');
props.setCount(props.count + 1);
}}
>
+1
</button>
);
}
我们在所有三个框架中都实现了上述代码。请注意,我们已将Console.log()放在关键位置以显示正在发生的事情。
您可以看到,这三个框架之间没有区别。所有框架都执行了所有代码,因此具有相同的控制台输出。这是有道理的,因为该应用程序第一次执行和渲染时,该框架别无选择,只能在root组件处启动执行,然后下降到孩子并沿途执行每个组件。
现在让我们与组件进行交互,并观察日志的不同。
这是我们开始注意到框架之间的差异的地方。请注意,由于交互作用,所有三个框架都将+1施加+1,但仅反应会导致所有组件重新执行并重新印刷组件的日志。那么为什么有区别?
反应是粗粒反应性的。这意味着React重新渲染始于拥有状态的组件,然后React向下降低组件树。另一方面,固体和Qwik具有细粒度的反应性。这意味着状态的变化与组件无关,而与需要更新的DOM节点直接相关。最终结果是React重新执行了组件,而Solid和Qwik只需要更新DOM状态。短路重新执行组件和重新创建vdom是固体是目前最快的框架之一的原因。
虽然执行较少的代码在更新中很重要,但如果我们可以在初始渲染上保存执行,那就更好了。因此,让我们看看涉及HTML预先渲染时会发生什么。
HTML预渲染
在用户凝视空白屏幕时,进行应用程序的客户端渲染(CSR)可能需要大量时间。引入了HTML的预渲染来解决此特定问题。预渲染的目的是向用户显示统计页面,并在后台使页面交互式。
您如何预渲染HTML?好吧,这很简单。您只需在服务器上执行应用程序(SSR/SSG),而不是在客户端上执行应用程序。应用程序构建HTML后,您将HTML发送到客户端(或在CDN处缓存以供以后发送)。
![表明在SSR/SSG Compering React,Solid和Qwik上执行的记录函数的表的屏幕截图。](
请注意,就像CSR一样,所有框架都必须执行从根开始的所有组件。这是有道理的,因为执行应用程序代码是框架如何学习应用程序的方式。
使HTML互动
一旦我们对客户端进行了预渲染的应用程序,我们就需要使其进行交互。最初,当引入HTML预渲染时,该框架仍将进行CSR,并将静态内容替换为客户端渲染的内容。从这个意义上讲,“水合”只是CSR的重新品牌。从那时起,CSR变得更聪明,现在它尽可能地重复使用HTML,但在其核心方面,水合仍然只是CSR。
,但是现在我们开始看到差异。请注意,React和Solid必须在客户端上重新执行应用程序代码,而Qwik不必这样做。那么发生了什么?好吧,请记住,水合只是重新品牌的企业社会责任。因此,从这个意义上讲,这是有道理的。该框架需要重新执行从根部开始并降至儿童的应用程序。此执行的目的是收集有关应用程序的组件边界,事件侦听器和反应性图。
。实心不必做不必要的工作,但仍需要执行组件以重建细粒度的反应性图。 Qwik能够在服务器上序列化反应性图,因此可以跳过客户端上的步骤。
在启动上执行代码问题吗?好吧,这取决于您的应用程序的大小。在我们的玩具演示中,它的区别几乎没有。问题在于,这一成本与应用程序的复杂性成正比。当您开始一个项目时,水合不是问题,但是随着项目的增长,它将成为一千个削减的死亡问题。
。请记住,水合只是更名的企业社会责任。 CSR速度是一个问题,因此我们引入了HTML预渲染。预渲染的HTML帮助解决了视觉问题,但它没有针对时间进行交互的时间。 (相反,可以提出一个论点,即添加预渲染的HTML为浏览器带来了更多的工作,因此延迟了交互的时间。)
预渲染HTML后的互动性
让我们看一下交互性会发生什么。
交互性与CSR的交互性非常相似。 React会导致所有组件重新执行,但是SolidJ和Qwik仅执行事件处理程序。
那为什么要这么做呢?请注意,Qwik仅执行了服务器上的组件,但从未在客户端上执行。在初始的互动步骤和交互性步骤中都没有。这意味着在这种情况下,Qwik无需将组件代码下载到客户端。 (在其他情况下,Qwik可能必须下载组件代码,但是这些代码并不常见。)
虽然SolidJs在交互时没有执行代码有效,但它确实必须下载代码并在一开始就执行该代码以使应用程序交互。即使SolidJ不必再执行代码,也已支付下载和执行价格。
重复性
ROSUMASIES是一种框架恢复其状态而无需重新执行客户端上的应用程序组件的方式。这是通过不仅序列化应用程序状态,还可以序列化HTML预订阅期间的框架状态来完成的。通过序列化组件边界,事件侦听器和反应性图,可以继续执行服务器关闭的位置。客户端可以恢复服务器关闭的执行情况,从而节省重新执行组件树(水合)以进行交互的成本。将其与细颗粒反应性结合在一起,大多数情况下,框架不必下载组件。
Qwik也无法进行水合,因为水合代码(组件)未下载给客户。
还有另一个值得一提的。水合必须在应用程序交互之前执行。是的,执行可能是懒惰的,但是在水合执行之前,该按钮不会处理事件。重复性是直接的。在执行任何代码之前,按钮进行交互。
重复性由于相互作用而恢复了框架的状态,而水合必须在交互前进行。
代码重复
水合是在下载和执行两次的应用程序时,一次是HTML,并且再次为JavaScript。 ROSMUMAISIOS允许您删除应用程序代码。客户要么为特定部分下载HTML或JavaScript,但很少两者。
懒负荷无济于事
水合要求该框架执行组件以恢复事件听众和反应性图。在组件树中插入懒惰的边界无助于防止下载代码。在水合过程中,该框架将被迫热切下载并执行代码。
结论
我们构建了一个简单的应用程序,其中包括状态,渲染和互动性分布在组件中,以模拟框架如何处理组件执行。在CSR/SSR/SSH的最初渲染过程中,行为是无法区分的。但是互动性展示了细粒反应性的优势,这使框架可以显着减少需要在客户端上存在的代码量。将细粒度反应性与可重复性相结合,可以使框架跳过大多数组件的下载和执行,从而产生即时启动。尽管水合和可重复性都使应用程序交互,但它们以截然不同的方式进行。