关于javascript:Angular之父为什么怼React

37次阅读

共计 4027 个字符,预计需要花费 11 分钟才能阅读完成。

大家好,我卡颂。

前几天,Angular之父 Miško HeveryDan在推上产生了一段乏味的对话,对话背景大略是:

  1. 传统 SSR(服务端渲染)场景下应用的技术叫HydrationMiško 曾向 Dan 演示了一个新技术概念 —— Resumable
  2. Dan认为这项技术不可行
  1. MiškoQwik 框架中实现了Resumable
  2. Dan示意在 React 中咱们之所以没有思考 Resumable,并不是因为框架不好接入,而是因为Resumable 并不是更优解
  1. Miško示意这是吃不到葡萄说葡萄酸

那么,Resumable到底是什么技术?他和 React 在推动的 RSCReact Server Component)有什么区别?Miško 为什么会作出上述舆论?

让咱们通过本文理解一下。

欢送退出人类高质量前端交换群,带飞

Resumable(复原)是什么

Resumable的概念源于一次思路的转变。

尽管支流前端框架都反对 SSR,但不论是ReactVue 还是Angular,他们都是CSR(客户端渲染)优先。

在这些框架中,SSR是在 CSR 的根底上附加的新性能。

正是因为传统前端框架都是 CSR 优先 的产物,才导致一些常见 SSR 问题,比方:

  • 首屏渲染时,页面短时间无奈响应交互,因为此时框架还未 hydrate 实现
  • 即便仅有局部内容须要交互,但整个页面还得全量hydrate

这些问题拉低了 SSR 场景下的 FCP(First Contentful Paint)与 TTI 指标(time to interactive)。

下图展现了 SSR 场景下 hydrate 的流程,包含 4 个步骤,只有在整个流程实现后利用能力响应交互:

  1. 下载HTML
  2. 下载所有 JS 文件
  3. 解析、执行 JS 文件(次要是框架及其依赖,还有业务逻辑代码)
  4. 绑定事件(即 hydrate 操作)

在某些利用场景(比方电商、博客)下,除了第一步,其余步骤可能不是必须的。

比方,对于一个电商商品详情页,除了展现商品所需的 HTML 外,其余都不是首屏渲染所必须的。

这就是 Qwik 框架中 Resumable 技术的设计理念 —— HTML优先,JS按需下载:

要实现 Resumable,须要摈弃传统框架以CSR 为根底(用 JS 生成 HTML 为主)的思路,转而以 SSR 为根底(以服务端生成 HTML 为主),再在此基础上附加 CSR 性能。

为什么叫 Resumable?

Resumable的理念概括起来就是 按需下载、执行 JS

所有 JS 代码的下载及运行会提早到须要的时候再执行。在如下官网示例 1 中,会渲染一个按钮,按钮的点击回调对应代码 不会在首屏渲染时下载:

export default component$(() => {
  return (
    <button
      onClick$={() => {
        // 这部分代码不会在首屏渲染时下载
        console.log('click');
        const div = document.querySelector('#container')! as HTMLElement;
        div.style.background = 'yellow';
      }}
    >
      执行
    </button>
  );
});

只有在点击按钮时,对应代码才会被下载并执行:

这就使得首屏渲染时须要下载及执行的 JS 文件大大减少,进步了 FCPTTI指标。

实际上,如果以 Chrome lighthouse 的评分作为评判根据,其余框架的确都难以望 Qwik 的项背

这项技术之所以叫 Resumable(复原),是因为它与传统Hydration 技术在首屏渲染时客户端逻辑的区别。

传统 Hydration 技术在首屏渲染时,客户端(比方浏览器)会全量执行框架代码与业务逻辑代码,并在此过程中实现:

  • 框架组件对应的树状数据结构初始化(比方在 React 中叫 Fiber 树,在 Vue 中叫 VNode 树)
  • 组件内状态初始化
  • 事件绑定

而以上过程在 Resumable 技术中是产生在服务端的。比方,对于上述按钮的例子,点击回调对应的下述代码会在服务端生成 HTML 时实现序列化:

onClick$={() => {console.log('click');
  const div = document.querySelector('#container')! as HTMLElement;
  div.style.background = 'yellow';
}}

序列化后的数据会以 HTML 属性 的模式存在:

当点击事件产生后,框架的前端局部会依据 HTML 属性(示例中的on:click 属性)向后端申请具体的 JS 代码(即点击回调对应的代码)并执行。

一句话总结就是 —— 在 Resumable 技术中,所有以 SSR 为主,局部在 SSR 时未实现的操作(比方交互逻辑对应代码)会在须要触发时(比方交互产生时)再 复原 执行,所以这一技术叫Resumable(复原)。

与 RSC 的区别

同样是 SSR 相干技术,React团队主导的 RSCReact Server Component)与Resumable 有什么区别呢?

在解说他们的区别前,咱们要先理解一个背景常识:ReactCSR 优先 的框架,而且他曾经呈现很多年了(13 年问世)。

尽管这些年呈现了很多优良的框架技术(比方 SignalAOT),但React 始终保持这套 重客户端运行时 技术架构。

在公布 React Hooks 后,React团队逐步将重心转移向服务端。因为其技术架构偏差客户端运行时,所以将 React 间接革新为 SSR 优先 显然不事实。

为此,React团队的策略是 —— 提供 SSR 能力,再让其余 SSR 优先 框架接入(次要是Next.js)。

所以,ResumableRSC 的次要区别其实体现在框架底层实现层面。

区别 1:序列化形式

最大的区别体现在 序列化数据 形式的不同。

Resumable 技术下,SSR时会将大量数据序列化为 HTML 属性或正文,比方:

  • DOMQwik 组件的关系
  • 状态(是的,状态都会在服务端序列化为 HTML 属性,再在客户端复原)
  • 代码逻辑(比方上述示例中的点击回调逻辑)

服务端实现了大部分工作,客户端须要做的仅仅是按需反序列化数据,并执行对应逻辑。

RSC 中,服务端组件会被序列化为一种自定义 JSX 协定,并被流式传输。之所以没有被序列化为 HTML 字符串(就像 Resumable 那样),是因为数据被反序列化后并不间接是 HTML,而是JSXJSX 经由 React 解决后才会映射到HTML,这么做能放弃服务端组件的子孙客户端组件不失落状态。

比方如下 RSC,依据id props 从数据库取不同数据,再将数据传递给子组件(客户端组件):

function ServerCpn({id}) {const data = db.get(id);
  return <ClicentCpn {...data} />;
}

id props 变动后,ClicentCpn组件内的状态并不会失落。就是因为服务端传输来的 ServerCpn 是一种自定义 JSX 协定,而不是 HTML 字符串。

区别 2:变动监测形式

通过区别 1 能够发现,RSC中序列化的数据形容的是组件级别的内容(JSX形容组件)。

Resumable 中序列化的数据粒度更细(比方形容点击事件的回调逻辑,或者某个状态)。之所以会有这种区别,是因为两个框架采纳不同的变动监测形式。

当状态变动后,React须要遍历残缺的组件树能力计算出 状态变动产生的影响。所以序列化数据只须要形容组件级别的内容就行。

Qwik(实现Resumable 技术的框架)应用 Signal 监听状态变动,这使得他能精确定位 状态变动所产生的影响,即精确定位状态变动须要反序列化哪些数据。

区别 3:后续的倒退

因为 React 是重客户端运行时的框架,所以尽管 RSCSSR技术,他的后续倒退还是会与重客户端运行时的技术绑定(比方SuspenseSelective Hydration)。

Resumable是重服务端技术,所以后续倒退应该会围绕服务端开展,比方:

  • 反对更多类型数据的序列化(以后不反对 class 序列化)
  • 反对序列化数据的流式传输
  • 反对对 是否序列化数据 更精密的管制

Miško 的想法

理解了这些技术细节,让咱们回到开篇,为什么 Miško 会怼 React 呢?

实际上,这并不是 Miško 第一次对 React 发表认识。之前 Miško 就曾示意:即便 React Forget Compiler 胜利问世,他也没法解决 props 下钻 场景下的性能问题,并以此论证 Signal 技术的优越性:

在这里咱们不比拟技术优劣。只是说单纯用脚投票,除了 React 外,的确有很多框架都应用了 Signal 相干技术,比方:

  • Vue
  • Preact
  • Qwik
  • 新版Angular
  • Solid.js

Miško 看来,React团队之所以不采纳更优良的技术,是因为一旦采纳新技术,就没法完满的向后兼容,势必造成社区生态的割裂。

作为 Angular 的作者,Miško对这种结果再分明不过了。

然而,React团队却认为 —— React之所以没有采纳这些技术,是因为本身的技术路线更优良。

这里 Dan 举出的例子是 HooksRSC

本文曾经做过 RSCResumable的比拟。在笔者看来,两者是不同技术路线(CSR优先还是 SSR 优先)下的优良代表。

但就 Hooks 而言,笔者认为 Hooks 优良在其理念,而不是实现。同样基于 Hooks 理念实现的 Vue Composition API 在应用体验上比 React Hooks 更佳,比方:

  • 没有闭包陷阱
  • 没有显式指明依赖的心智累赘

之所以同样理念的不同实现应用体验不同,齐全是因为底层的技术实现区别造成的(这里指 底层变动监测形式)。

所以,从这个角度想,笔者并不同意 React 团队的说法。

我想,这也是为什么 Miško 会认为 React 团队吃不到葡萄说葡萄酸。

总结

大佬们的探讨总是感性、相互尊重且克服的。Miško在后续也示意了本人对 React 的误判。

Qwik v1.0 公布时,Dan第一工夫送上祝愿。

有意思的是,对于 Dan 的祝愿,Miško回复道:咱们都站在伟人(指React)的肩膀上。

这是不是说,我还是比伟人要高呢?

正文完
 0