Qwik 与 React Hydration 有何不同

更新日期: 2024-03-21阅读: 1.8k标签: React

在本文中,我将深入介绍 Resumability (可恢复性),这一 Qwik 用来解决繁杂的客户端 JavaScript 问题的技术。我还将说明这和 react 的处理方式有何不同。

QwikSchool.com 上有一个很棒的 Qwik 视频入门课程,教程会涵盖我在本文中讲的一些东西。但对我来说,阅读是更适合我的学习方式,使用类比的方式学习,我就能学的更快。所以,我会在本文中用「酒吧」和「啤酒」来做些类比,让你更好理解。


React Hydration 是如何工作的

想象一下,你走进一间酒吧坐下,但酒保没有让你点单,而是直接拿了个大杯子,倒进去 6 品脱(品脱 pint 是英式和美式体系中常用的体积单位)啤酒。当酒保确认杯子确实能装 6 品脱酒后,他就会把酒全倒掉。然后,酒保会递给你(客户端)一个空杯子,再给你倒上 6 品脱酒。

你最终需要为这 12 品脱的酒付钱,而其中 6 品脱是被倒掉的,也就是说其中一半其实是你当时不需要的。

React Hydration 就是这么工作的。


Qwik Resumability 是如何工作的

想象一下,你走进一间酒吧坐下,酒保会让你点单。你说:”请给我一品脱啤酒“。酒保接着会将一品脱啤酒倒入一个正常大小的杯子,并递给你。

你将为这一品脱酒付钱。简而言之这就是 Qwik Resumability。

从顶层去看,你会发现,相比于 Qwik,React 的处理方式存在着巨大的性能浪费,且没有一个非常精准的方法来确定什么时候需要进行处理,需要处理多少。


重现 React Hydration

我们继续使用前文提到的例子,酒保把 6 品脱啤酒倒入一个大杯子,然后全倒掉,最后递给你(客户端)一个空杯子,再重新倒酒。

React 在服务器上进行渲染时,就会发生这样的事。应用程序在服务端构建,之后被丢弃。服务器会把 html 发送到客户端,随后发送一大段 JavaScript 代码,这些代码是用于在客户端(浏览器)上重现服务端渲染的过程。如果在重现过程中发生什么异常,导致失败,你会在控制台看到 Hydration 的相关错误信息。

服务器需要构建一次页面,如此它才能知道自己要向客户端发送什么东西,这就解释了 React Hydration 重现 过程中的一半。但也许你会问,为什么在我啤酒的比喻里,6 品脱是一次倒出来的?答案就是「路由分块」。


什么是「路由分块」?

不同版本的 React 框架可能会略微有些不同,但总的来说「路由分块」是在描述这样一种技术:服务器在对 React 应用进行构建时,框架会基于用户正在查看的页面路由,找出所需的 JavaScript。例如,如果用户正在访问 /dashboard 路由,那他需要的 JavaScript 和访问 /settings 路由的用户是不同的。页面路由会决定哪些 JavaScript 应该被包含在分块里。这技术真是太智能了,不过我们还能做的更好。


什么是「动态组件分块」(Dynamic Component Chunking)?

Qwik 的处理方式颗粒度更细。它不使用基于用户正在访问路由来决定要包含哪些 JavaScript 的方法,它把 JavaScript 分成小的多的多的小块。这些更小的块可以被更加快的发送到客户端。不仅如此,Qwik 能够查明用户正在访问给定路由的行为,并以此提供这些更小的 JavaScript 块。


我需要 $

在 Qwik 库中,不管是什么都带着 $ 后缀。比如,下面这个简单的组件,我们用 component$() 把他包起来了。

import { component$, $ } from '@builder.io/qwik';

const SimpleQwikComponent = component$(() => {

const handleClick = $(() => {
console.log('Hello world!');
});

return (
<div>
<p>Hello, I'm a simple Qwik component</p>
<button onClick$={handleClick}>Click me</button>
</div>
);
});

export default SimpleQwikComponent;

多亏了 $ 语法,Qwik 能容易的对分块边界进行优化,这样一来就能构建出更小的独立 JavaScript 分块。

另外,这也有助于在根据需要时提供这些小 JavaScript 块。

以 onClick$ 为例。这段代码实际上仅在用户点击按钮时是需要的。如果用户没有点击按钮,这段在控制台输出 Hello world! 的 JavaScript 将仅存在于浏览器缓存(已由 Qwik 的 service worker 拉取),它不会被优先下载,而是会等到实际需要的时候在下载。

换一个例子,想想看,如果有一个大型应用程序,它有着很多不同的交互区域,你是否觉得:「所有用户在任何时候都需要全量的 JavaScript」?也许,一些用户某些时候只是需要其中一部分 JavaScript,你觉得呢?


Service Worker

事情变得有趣起来了。你可能听说过 Partytown,这是 Qwik 的创建者做的一个开源库,它能帮你把一些客户端脚本(比如 Google Analytics)加载转移到 service worker 上。通过将不必要的脚本转移到 service worker 上,我们解放了浏览器主线程,我们的应用程序可以更有效率的载入自己的代码,让应用程序表现的更出色。

不过...

默认情况下,Qwik 利用 service worker 来载入你的应用程序代码!那么说不定,从另一个角度看,这意味着你可以继续在主线程载入 Google Analytics,但这么做对性能的影响应该也很有限。

一旦通过 service worker 载入 JavaScript,JavaScript 就会被浏览器缓存,所以下次用户访问时可能会重用已经下载的代码,Qwik 会从这些缓存中载入,而不是从网络。现在我的啤酒类比法不太好说明这个问题,但... 希望你能理解这些点。


正式的例子

举个例子,在我的站点上,每一个「帖子」页面都有一个 Reactions(反馈)组件。

就像下面这样:


这个组件负责这些工作:

  • 做一个客户端 GET 请求,获取用户可以针对本贴所有的反馈信息。
  • 点击这些反馈按钮,会做一个客户端 POST 请求提交反馈。

Qwik 的处理策略非常智能。

让我说说 Qwik 厉害在哪里。下面是我那篇帖子的 network 选项卡截图:


到目前为止,仅有差不多 19kb 的 JavaScript 在页面上载入了(这是 Qwik 的核心代码)。

我们向下滚动一些,当 Reactions 组件进入视口,Qwik 会载入所需的独立 JavaScript 分块,即用来展示那些笑脸的分块,并启动一个客户端 GET 请求来获取。

不过等等,还没结束哦。

和 Reactions 组件进行交互(这会导致发送一个 POST 请求)后,你会发现 Qwik 又一次载入了所需的 JavaScript 分块,用于让按钮点击逻辑生效。

这些分块非常小,在我这个例子中,大部分尺寸都小于 1kb!


Qwik 的思路

这就是 Qwik 的思路。只在所需的时间,载入所需的 JavaScript。对于像 Reactions 这样的组件来说,这一点尤为重要。Reactions 组件位于一个基本上可以被视为「静态页面」的页面底部。这意味着该页面不需要从服务器端拉取数据或进行服务器端渲染,因此其加载速度会比需要服务器端渲染(SSR)的页面更快。然而,尽管 Reactions 组件位于这样的静态页面中,它仍然需要执行 GET 和 POST 请求。

大部分时候,我帖子的读者不会滚动到页面最下方,因此他们确实不需要页面那部分的任何数据,不需要载入那部分的 JavaScript。不过,如果读者要向下滚动,Qwik 会介入并智能的选择「何时载入」、「载入什么」。太有才了!


React 的思路

当然,可能用 React 也能达成类似的效果吧。你可以自己整一个 intersection observer,并把它和 React 的 lazy / suspense 技术结合起来,这样数据(以及交互所需的 JavaScript)获取仅会在组件滚动到视口的时候进行,不过呢,这些东西都需要你作为一个开发者去考虑和优化,Qwik 可是替你把这些东西都考虑过了!


最后的想法

虽然酒吧和啤酒的类比可能看起来有点奇怪,但我相信在实际应用中,这个理论是站得住的:「你/用户」只应该在 需要的时候 点那些 你需要的为之付钱

老实说,应用程序代码之间有什么不同呢?无端地抛弃一半,不经询问的过度交付、过度收费,这真的没什么道理。讲真,我们只希望简简单单为那些我们点的东西付钱。

Qwik 团队撰写了一份技术说明文档,你应该去读一读:Resumable vs. Hydration。如果你想对 Qwik 感兴趣,那你应该了解一下!我在学习 Qwik 的过程中非常享受,并且我经常惊讶于不需要考虑太多,就能获得如此出色的性能。

本文译者为 360 奇舞团前端开发工程师 
原文标题:JavaScript on Demand: How Qwik Differs From React Hydration
原文作者:Paul Scanlon
原文地址:https://thenewstack.io/javascript-on-demand-how-qwik-differs-from-react-hydration/

链接: https://fly63.com/article/detial/12695

如何优雅的设计 React 组件

如今的 Web 前端已被 React、Vue 和 Angular 三分天下,尽管现在的 jQuery 已不再那么流行,但 jQuery 的设计思想还是非常值得致敬和学习的,特别是 jQuery 的插件化。

React深度编程:受控组件与非受控组件

受控组件与非受控组件在官网与国内网上的资料都不多,有些人觉得它可有可不有,也不在意。这恰恰显示React的威力,满足不同规模大小的工程需求。

React框架学习_关于React两种构建应用方式选择

一般在传统模式下,我们构建前端项目很简单。就是下载各种js文件,如JQuery、Echart等,直接放置在html静态文件。Webpack则是JavaScript中比较知名的打包工具。这两个构建工具构成了React应用快速搭建的基础。

Gatsby.js_一款基于React.js静态站点生成工具

Gatsby能快速的使用 React 生态系统来生成静态网站,可以结合React Component、Markdown 和服务端渲染来完成静态网站生成让他更强大。

React创建组件的三种方式及其区别

React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归;具体的三种方式:函数式定义的无状态组件、es5原生方式React.createClass定义的组件、es6形式的extends React.Component定义的组件

react生命周期详解_深入理解React生命周期

React主要思想是通过构建可复用组件来构建用户界面,每个组件都有自己的生命周期,它规定了组件的状态和方法需要在哪个阶段改变和执行。所谓组件就是有限状态机,,表示有限个状态以及在这些状态之间的转移和动作行为的模型。

React + Webpack 构建打包优化

React 相关的优化:使用 babel-react-optimize 对 React 代码进行优化,检查没有使用的库,去除 import 引用,按需打包所用的类库,比如 lodash 、echarts 等.Webpack 构建打包存在的问题两个方面:构建速度慢,打包后的文件体积过大

react router中页面传值的三种方法

这篇文章主要介绍React Router定义路由之后如何传值,有关React和React Router 。react router中页面传值的三种方法:props.params、query、state

react 高阶组件的 理解和应用

react 高阶组件简单的理解是:一个包装了另一个基础组件的组件。高阶组件的两种形式:属性代理(Props Proxy)、反向继承 (Inheritance Inversion)

react中的refs属性的使用方法

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!