原文:稀土掘金技术社区作者:黄山
如有侵权,请联系我们删除。
React 发布已经10 年了,我从事前端工作也快10 年了。说实话,如果没有Head First 系列书籍,我可能不会进入编程领域。
从头部开始
虽然这个系列书的内容现在看来可能已经过时了。
《Head First》系列书籍告诉我,编程对于刚接触该领域的学生来说非常容易理解,并且可以从中获得很大的自信和成就感。这种风格一直影响着我在学习、工作和教学的过程中,它力求把复杂的事物简单化、大众化,提炼出本质。
我认为前端渲染方法在过去10年里经历了三个主要阶段的演变。
无标题
最初的SSR:中,当时并没有分离出前端,通过JSP、ASP、Ruby on Rails、Django等MVC框架下的模板来渲染页面。这个舞台的明星是jQuery
前后端分离:由Node.js发布,是近十年来迄今为止最快的前端开发。 Angular、React、Vue 等框架是前后端分离的典型例子,我认为这是因为它变得越来越流行。事情变得更加复杂。前端可以专注于UI设计和交互逻辑。后端只需要提供API,不需要关心前端的具体实现。
同态前端:近年来,随着云原生、容器技术、无服务器、边缘计算等底层技术能力的日益普及,前端框架的发展势头强劲。它还被扩展到服务器端。前端开始寻求UX和DX之间的平衡
通过这篇文章,你可以了解近几年前端渲染模型的演变。让我们开始吧。
CSR – 客户端渲染
无标题
每个人都熟悉这一点。即前端页面在浏览器中渲染,服务器只是一个静态资源服务器(如nginx)。
最初的HTML 文件只是一个空壳,必须等到JavaScript 包加载并执行后才能与其交互。
优势
易于部署
页面切换和功能交互友好
复杂交互式应用程序开发的理想选择
有缺点
不利于搜索引擎优化
白屏时间长
可能需要复杂的状态管理。直到今天,国家控制的车轮仍在建造中。
SSR – 服务端渲染
无标题
为了解决SEO 和白屏问题,主要框架已开始支持HTML 字符串的服务器端渲染。
SSR 在服务器端执行数据拉取。由于服务器端距离数据源更近,因此拉取数据的速度更快。然而,这并非完全没有副作用。你必须等到服务器端数据准备好,并且TTFB(第一个字节的时间)比CSR要长一点。
SSR只准备初始数据和HTML。事实上,与CSR类似,它需要在浏览器端加载并重新渲染完整的客户端程序(更技术地说,水化/注水)。使DOM 具有交互性。
换句话说,FCP(First Contentful Paint)比CSR更快,但TTI(Time to Interactive)差别不大。它只是让用户更快地看到您的内容。
水化的主要目的是挂载事件处理程序、触发副作用等。
优势
搜索引擎优化友好
用户可以更快地查看内容
有缺点
部署环境要求。需要Nodejs等JavaScript服务器端执行环境
必须包含完整的JavaScript 客户端渲染器。 TTI还有改进的空间
SSG – 静态生成
无标题
对于博客或者公司主页等完全静态的页面,还可以使用SSG静态渲染。
与SSR 的区别在于SSG 在构建时呈现。
与CSR一样,它是静态的,因此不需要任何服务器端渲染运行时,并且可以部署到静态服务器。
VuePress、VitePress、Gatsby 和Docusaurus 等框架都属于SSG 类别。
优势
与SSR相比,它不需要服务器运行时或数据拉取,使得TTFB/FCP等更加复杂。
有缺点
与SSR类似,也有需要Hydrate的客户端渲染程序。对于以内容为中心的网站,您实际上不需要做太多事情,并且您的客户端程序仍然有进一步压缩的空间。
构建时渲染更加麻烦,因为如果内容发生变化就必须重新构建。
ISG – 增量静态生成
无标题
ISG是SSG的升级版本。解决SSG内容更改的麻烦问题。
ISG 在构建时预渲染页面,但有一个额外的服务器端运行时,可以根据特定的过期/刷新策略(通常使用stale-while-revalidate)重新生成页面。
逐渐补水- 逐渐补水
无标题
前面提到,传统的SSR通常需要客户端程序(上图中的Bundle.js)完全加载,并且只能在水合后检索交互页面,导致TTI缓慢。
最直接的解决方案是减小客户端程序的大小。既然如此,自然要考虑使用代码分割技术。这就是渐进水合作用的起源。
如上图所示,通过代码拆分将Foo和Bar提取为异步组件,可以减少主包的大小并提高TTI。
Foo 和Bar 可以在视口可见时、浏览器空闲时或根据某些策略按需加载和水合,例如React Concurrent Mode,它根据交互优先级加载。
React 18 正式支持渐进式水合(官方称为选择性水合)。
观看此视频,了解有关Progress Hydration 的更多信息。
SSR with streaming – 流式 SSR
无标题
这很容易理解。 ChatGPT 已经变得非常流行,尤其是最近。 ChatGPT API 有两种响应模式:常规响应和流式响应。
renderToString 正常响应。换句话说,SSR 会等待完整的HTML 渲染完毕,然后再将第一个字节发送到客户端。
renderToNodeStream 流响应。仅发送渲染的部分。与ChatGPT 聊天消息一样,它们逐字跳转,但虽然接收完整消息所需的时间相似,但用户体验却截然不同。
浏览器可以优雅地处理HTML 流并快速向用户呈现内容,而不是等待空白屏幕。
下图可以让你更直观的感受到两者的区别。
来源:https://mxstbr.com/thoughts/streaming-ssr/
来源:https://mxstbr.com/thoughts/streaming-ssr/
对于常规流式SSR来说,优化的效果可能没有我们想象的那么明显。这是因为框架需要等到数据拉取完成后才开始渲染。因此,除非你有一个相对复杂且较长的HTML 树序列,从上到下渲染需要很长时间,否则效果并不明显。
优势
与常规响应相比,流式响应可以提前TTFB 和FCP,并且浏览器不必等待空闲,可以连续绘制。
有缺点
拉取数据是TTFB/FCP中阻塞的主要原因。针对这个问题,下面的选择性补水就巧妙的解决了这个问题。
Selective Hydration – 选择性水合
无标题
Progressive Hydration 是Progressive Hydration 和SSR with Streaming 的升级版本。主要通过有选择地跳过“慢速组件”并避免阻塞,可以实现更快的HTML 输出,并且流式响应可以完成其工作。
慢速组件通常是需要异步检索数据、体积较大或执行相对复杂计算的组件。
典型的慢速组件是异步数据采集。如果没有开启选择性水合,则会等到所有异步任务完成后才开始输出。它必须准备好才能继续输出。
无标题
您可以使用最新的Next.js(当前为13.4)来演示它。
未启用选择性水合的Demo:
函数延迟(time:号){
返回新的Promise((已解决)=setTimeout(已解决, 时间))
}
/**
* 获取关键数据
*/
函数getCrucialData() {
返回延迟(1000).then(()={
返回{
data: Math.random(),
}
})
}
函数getData(time: 数字) {
返回延迟(时间).then(()={
返回{
data: Math.random(),
}
})
}
const Foo=async ()={
常量数据=等待getData(1000)
divfoo: 返回{data.data}/div
}
const Bar=async ()={
常量数据=等待getData(2000)
divbar: 返回{data.data}/div
}
/**
* 页
*
*/
导出默认的异步函数WithoutSelective() {
//获取关键数据
const importantData=等待getCrucialData()
返回(
分配
h1 未选择/h1
p此页面显示时没有选择性水合。 /p
pcrucial data: {crucialData.data}/p
福/福
酒吧/酒吧
/div
)
}
结果:浏览器等待响应3 秒。
这意味着只有在所有服务器组件准备就绪后才会输出实际内容。
开启选择性水合非常容易。只需将其包装在Suspend 中即可告诉React 这可能是一个“慢速组件”并允许跳过它。
导出默认的异步函数WithoutSelective() {
//获取关键数据
const importantData=等待getCrucialData()
返回(
分配
h1 未选择/h1
p此页面显示时没有选择性水合。 /p
pcrucial data: {crucialData.data}/p
悬念后备=\’fooloading\’
福/福
/悬念
悬念后备=\’酒吧加载\’
酒吧/酒吧
/悬念
/div
)
}
接下来我们看一下执行结果。
无标题
显然TTFB 提前了。但是,完整的请求时间保持不变。
一旦Foo 和Bar 准备就绪,Next.js 就会将渲染结果写入流中。你是怎么做到的?
只需查看HTML,您就可以知道:
无标题
对于慢速组件,React 首先渲染挂起后备内容,留下一个槽。
如果继续往下看,您将看到Foo 和Bar 的渲染结果。
无标题
然后用渲染结果替换槽。之后用于补水。
也就是说,在服务器端,Selective Hydration 在SSR With Streaming 的基础上,通过选择性跳过低优先级慢速组件(主要与FCP 等指标相关)来优化TTFB,并提供加速页面显示。
对客户进行选择性水化的过程与渐进式水化相同。
要了解有关选择性补水的更多信息,请查看以下文章:
18: 选择性补水新品
React 18 中新的Suspense SSR 架构
Islands Architecture – 岛屿架构
无标题
这两年,JavaScript已经成为一股小趋势。最值得注意的是Islands Architecture和React Server Component(RSC,React Server Component)。
他们的想法是渲染服务器端并删除不必要的JavaScript。
岛上建筑的主要代表是Astro。如上图,Astro在服务器端渲染后,默认情况下客户端是没有客户端程序和水合过程的。需要JavaScript 扩展来实现动态交互的组件必须显式标记为孤岛。
这类似于渐进补水的含义。但仍然存在很大差异。
孤岛是JavaScript 上下文中的交互式扩展方法。正如Astro 所解释的,您可以将“岛”视为静态(非交互式)HTML 页面中的动态岛。
每个岛屿都独立加载并部分水化。渐进水化是整个树只是延迟水化的一个分支。
岛屿可以独立于框架。
删除JavaScript 可以缓解典型的SSRTTI 问题。但孤岛架构并不能适用于所有场景。换句话说,当静态页面的百分比远高于动态页面的百分比时,删除JavaScript 的好处更大。
React Server Component – React 服务端组件
无标题
在作者看来,React Server Component(RSC)本质上和孤岛架构的目的是一样的:去除JavaScript。只是执行手段不同而已。
这是官方Next.js 文档中的示例图。与岛式架构类似,静态内容建议使用服务器组件(SC),交互增强可使用客户端组件(CC)。
无标题
顾名思义,RSC是一个只能运行在服务器端的组件。让我们快速比较一下两者之间的差异。
服务器组件客户端组件执行环境服务器-服务器+客户端仅客户端服务器组件所依赖的JavaScript 相关程序对客户端不可见。如果在这里实现,“JavaScript Removal”必须打包并分发给客户端。无需补水。支持的asyncYN 支持事件和副作用。
RSC 的好处与React Hooks 之前的功能组件: 类似。它只是一个常规函数,不能使用钩子,没有状态,并且只被调用一次。
有关RSC 的更多信息,请参阅Next.js 文档。 React官方讨论组也是一个直接学习的好地方。
那么它和岛上的建筑相比怎么样呢?
优势
尽管服务器和客户端组件都是React 框架的组件,但它们具有统一的思维模型,但也存在一些差异。
React Server Component 是集成在React 框架下的原生解决方案,支持与Selective Hydration 一起使用。岛屿建筑只是一种建筑模式。
更详细和灵活的组合是可能的。
有缺点
服务器和客户端组件之间仍然存在显着差异,开发人员必须规划服务器和客户端之间的边界。早期起步是有一定门槛的。当然,岛屿上也会出现类似的问题。
总结
这篇文章比较长,所以我总结了这些渲染模式的发展历史和关系。
无标题
技术迭代是有动机和背景的。不建议为了流行而编程。在大多数情况下,“知道发生了什么以及为什么”就足够了。
#以上有关现代前端框架渲染模式的相关内容摘自网络,仅供参考。相关信息请参见官方公告。
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/92780.html