2
本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一时间和你分享前端行业趋势,学习途径等等。
更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,包含一线大厂面试完整考点、资料以及我的系列文章。

在Javascript生态系统中保持现状并不适合不爱学习的人。

对于那些刚进入这个行业的人来说,要在新的库、框架、概念和强烈的意见中关注正在发生的事情是很有挑战性的。

这节课,我们来学习一下 Javascript 生态系统中框架的最新进展。

我们通过研究过去在构建大型web应用时的痛点来了解当前的情况。与其关注解决方案的扩展,我们不如深入研究根本问题。每个框架都给出了不同的答案,并做出了不同的权衡。

网页的手绘历史

Web 开始时是以静态文件连接在一起的。人们可以提前准备一份文件,并把它放在电脑上。

现在最酷的事情是,其他人可以访问它--而不必面对面的交接,相当方便。

在某种程度上,我们认为让这些文件成为动态文件会很酷。于是,出现了 CGI 这样的技术,使我们能够根据请求提供不同的内容。

然后我们有了像Perl这样的表达式语言来编写这些脚本。影响了第一种明确为网络建立的语言--PHP

PHP的创新之处在于将HTML直接与后端代码相连。这使得以编程方式创建嵌入动态值的文件变得容易。

Web 最重大的突破之一就是从这个开始的:

<html>
    <body>
        This document has been prepared ahead of time.
        Regards.
    </body>
</html>

到容易嵌入的动态值:

<html>
    <body>
        Y2K? <?php echo time(); ?>
    </body>
</html>

潘多拉的盒子打开了

这些动态页面很受欢迎。我们现在可以很容易地定制我们发送给用户的内容,包括启用会话的cookies。

基于服务器的模板框架在与数据库对话的语言生态系统中出现了。这些框架使得从静态页面开始到扩展到动态页面变得容易。

web 发展迅速,我们想要更多的互动体验。为此,我们使用了Flash等浏览器插件。对于其他事情,我们会在后端提供的HTML上 加上 Javascript片段。

像jQuery和Prototype这样的工具出现了,并抚平了Web API的粗糙边缘和竞争性浏览器之间的差异。

时间推进,科技公司越来越大,随着项目和团队的增长,更多的商业逻辑悄悄进入这些模板是很常见的。模板经常演变成访问全局变量的业务逻辑的混杂物。安全性成为一个问题,像SQL注入这样的攻击很常见。

最终来到了: Ajax: Web应用程序的新方法。

现在可以做的新事情是异步更新页面,而不是同步刷新。

这种模式被第一批大型客户端应用程序如谷歌地图和谷歌文档所推广。

我们开始看到 Web 对桌面型软件分发的力量。与在商店购买软件的光盘相比,这是一个重大进步。

Javascript变得很大

当node出现的时候,它所带来的新事物是用与前端相同的语言来编写后端。所有这些都是开发人员所熟悉的异步优先模式。

这一点过去(现在也是)很有说服力。随着越来越多的企业上线,竞争优势在于能够快速发货和迭代。

Node的生态系统强调重复使用小型的单用途包,可以直接并完成各自的任务。

前端与后端分离

我们对能够与桌面和移动设备相媲美的Web的渴望继续增长。现在有一系列可重复使用的 "widget "库和工具,如 jQuery UI、Dojo、Mootools、ExtJs和YUI等。

我们在前端做了更多的点缀。这通常会导致在前端和后端复制模板。

像Backbone和Knockout这样的框架出现了,还有其他许多框架。它们通过MVC、MVVM等架构为前端增加了关注点的分离,并与我们收集的所有小工具和jQuery插件兼容。

增加结构有助于扩展所有这些前端代码。并加快了从后端转移模板的速度。

我们仍然在编写微调的DOM操作来更新页面并保持组件同步。这个问题并不简单,与数据同步相关的bug很常见。

在谷歌的支持下,Angular登上了舞台。它通过增强HTML的动态性,促进了生产力的提高。它配备了双向数据绑定,以及一个受电子表格启发的响应式系统。

这些声明性的双向绑定删除了许多必须更新的东西的模板。这很好,让我们的工作效率更高。

随着事情的扩大,它变得很难追踪到什么在变化,并且经常导致性能不佳。更新的周期会发生,占据了主线程(今天像Svelte这样的库保留了双向绑定,同时减轻了它们的缺点)。

除了移动端的兴起,这些提高生产力的框架加速了前端后端的分裂。这为探索强调这种解耦的不同架构铺平了道路。

这是JAMstack理念的一个主要部分,它强调提前预制HTML并从CDN提供服务。

在当时,这是对提供静态文件的一种回溯。

但现在我们有了基于git的工作流程,有了强大的CDN基础设施,不需要依赖远在天边的中央服务器,有了与独立API对话的解耦前台。把静态资产放在CDN上的运营成本比运营服务器低得多。

今天,像Gatsby、Next和其他许多工具都利用了这些想法。

React 增长

挥挥衣袖,快步进入大科技时代。我们正试图快速行动,打破常规。

对于那些进入该行业的人来说,Javascript是个大问题,建立一个由独立后端支持的解耦SPA正成为现状。

React的诞生在于Facebook 遇到的几个挑战:

  1. 当数据频繁变化时的一致性。保持许多小工具之间的同步仍然是一个重大挑战。数据流缺乏可预测性,这在规模上是有问题的。
  2. 在组织上扩大规模。进入市场的时间和速度是优先考虑的。入职的新开发人员必须能够迅速上手并富有成效。

React诞生了,你可以做的很酷的新事情就是声明式地编写前端代码。

前端关注点的分离是著名的重新思考,以前的MVC框架无法扩展。

从模板升级到Javascript驱动的JSX,最初是被讨厌的。但我们中的大多数人都想通了。

组件模型允许解耦独立的前端团队,他们可以更容易地在独立组件上并行工作。

作为一个架构,它允许组件的分层。从共享的基元,到组成到页面根的有机体。

单向的数据流使数据流更容易理解、跟踪和调试。它增加了以前很难找到的可预测性。

虚拟DOM意味着我们可以写一些函数来返回用户界面的描述,并让React来处理困难的部分。

这解决了数据频繁变化时的一致性问题,并使模板的构成更符合人体工程学。

规模化的React - 冲击CPU和网络极限

再挥挥衣袖。React大获成功,已经成为行业标准,甚至对那些不需要它的网站来说也是如此。在天平的另一端,我们开始看到一些限制。

与CPU对抗

DOM是React模型的一个问题。浏览器并不是为了在连续的渲染周期中不断创建和销毁DOM节点而建立的。

就像任何可以通过引入新的代理层次来解决的问题一样,React把它抽象到虚拟DOM后面。

人们需要在100毫秒内感知到反馈,这样才能感觉到流畅。而在做滚动等事情时则要低得多。

与单线程环境相结合,这种优化成为高度互动应用的新瓶颈。

当虚拟DOM和真实DOM之间发生调和时,大型互动应用程序对用户的输入变得毫无反应。像长任务这样的术语开始出现了。

这导致了在2017年对React进行了整体重写,其中包含了并发模式的基础。

运行时间成本不断增加

同时,更快的速度意味着要运送更多的代码到线下。由于浏览器需要大量使用Javascript,启动时间过长是一个问题。

我们开始注意到所有隐含的运行时成本,不仅是HTML和虚拟DOM,还有我们编写CSS的方式。

组件模型使我们在CSS方面的经验更加顺畅。我们可以将样式与组件放在一起,这提高了可删除性。对于那些以前害怕删除CSS代码的人来说,这是一个非常好的属性。

我们一直在摆弄的级联和所有的特殊性问题都被JS库中的CSS抽象化了。

这些库的第一波往往带有隐含的运行时成本。我们需要等到组件被渲染后再将这些样式注入到页面中。这就导致了样式问题被植入Javascript捆绑包。

在规模上,性能差往往是千夫所指,我们注意到了这些成本。这导致了新的JS库中的CSS,它通过使用智能预编译器来提取样式表,专注于没有运行时间成本。

网络效率低下和渲染受阻的组件

当浏览器渲染HTML时,像CSS或 scripts 这样的渲染阻断资源会阻止HTML的其他部分显示出来。

在一个组件的层次结构中,父组件经常成为子组件的渲染障碍。在实践中,许多组件依赖于数据库的数据和CDN的代码(通过代码分割)。

这往往会导致顺序阻塞的网络请求的瀑布。组件在渲染后获取数据,解锁异步子组件。然后再获取他们需要的数据,重复这个过程。

此后,React发布了Suspense,帮助平滑页面的加载阶段。但在默认情况下,它并不能防止连续的网络瀑布。用于数据获取的Suspense允许 "边获取边渲染 "的模式。

Facebook是如何解决这些问题的呢?

我们继续绕行,了解React的一些权衡是如何在规模上得到缓解的。这将有助于构建新框架中的模式。

优化运行时间成本

在React中,虚拟DOM的运行时间成本是无法回避的。并发模式是在高度互动的体验中保持事物响应的答案。

在JS中的CSS领域,使用了一个名为Stylex的内部库。这就保持了符合人体工程学的开发者体验,而在渲染成千上万的组件时没有运行时间成本。

优化网络

Facebook通过Relay避免了顺序性的网络瀑布问题。

对于一个给定的入口点,静态分析决定了究竟哪些代码和数据需要加载。

这意味着代码和数据都可以在一个优化的graphQL查询中并行加载。

这比初始负载和SPA转换的顺序网络瀑布要快得多。

优化Javascript包

这里的一个根本问题是运送与特定用户无关的Javascript。

当有A/B测试,功能标记的体验,以及针对特定类型和群组的用户的代码时,这就很难了。还有语言和地区设置。

当有许多分叉的代码分支时,静态的依赖关系图无法看到在实践中为特定用户群一起使用的模块。

Facebook使用了一个由AI驱动的动态捆绑系统。这利用了其紧密的客户-服务器集成,在运行时根据请求计算出最佳的依赖图。

这与一个根据优先级分阶段加载捆绑物的框架相结合。

生态系统的其他部分呢?

Facebook拥有复杂的基础设施和多年来建立的内部库。如果你是一个大的科技公司,你可以夹带大量的资金和资源来优化这些远规模的权衡。

这为前端产品开发人员创造了一个成功的坑,让他们在保持性能的同时完成事情。

我们中的大多数人都没有建立一套像Facebook那样规模的应用程序。不过,在很多大型组织中,性能是热门话题。我们可以从这些模式中学习--比如尽可能高的获取数据,并行化网络,以及使用内联要求等等。

大型科技公司经常在内部推出自己的应用框架。使得许多解决方案散落在不同的用户区库中。

这导致了许多人有Javascript生态系统疲劳和框架倦怠。

Javascript的世界:分散的、分裂的、无领导的

我们正处于默认SPA的时代。这就是进入这个行业的人的现状。

React是无可争议的冠军,而我们看到了大规模的权衡。

React提供了一个层。把其他必要的层留给了生态系统,造成了每个重要方面的流失:路由、状态管理、数据获取等等,每个方面都有自己的概念和API。

不可变与可变,带有类的OOP与函数式的OOP,这些辩论和库都在蓬勃发展。

今天,许多开发者沉浸在做出何种选择和如何架构事物的不确定性中。

起来,起来,React替代品的骑手们!

组件是粘性的。但运行时间成本、Javascript驱动的JSX以及复杂性都有待讨论。

许多并非来自大型科技公司的草根替代品获得了广泛的认同。

Vue

当人们在评估迁移到Angular 2或React时,Vue填补了入门门槛低的空白。

你不必在复杂的webpack配置上大费周章。你可以从CDN上下载并开始使用对许多开发人员来说很直观的模板来构建组件。

核心团队可以使用路由和样式等核心组件,从而减少决策疲劳。

它还通过对模板进行静态分析,缓解了React调和算法的某些方面,以实现优化,加快运行时间。被称为编译器告知的虚拟DOM。

Svelte

Svelte开创了预编译的方法,消除了我们在运行时看到的复杂性和开销。

它完全摒弃了虚拟DOM,因此不受写Javascript的不可变风格的约束,可以做更新状态等事情。对许多人来说,这是一个更简单、更理智的 Web 构建模式。

Solid

Solid 有一个直接的和可预测的响应式模型,其灵感来自于Knockout。像React一样,它摒弃了模板,以简化函数的可组合性。

React采取的方法是不断重新渲染。Solid只渲染一次,然后使用一个精简的响应式系统来进行细粒度的更新,而没有虚拟DOM的开销。

Solid看起来就像我们许多React开发人员希望使用钩子的新代码的样子。它的API可能更符合人体工程学,平滑了许多事情,如钩子依赖数组,它的重点是细粒度的响应式和可组合的基元。

互相学习

关于这些框架中的每一个,都有很多东西可以说。每个人都根据他们的基本模式和偏好做出了不同的权衡。

在现实中,进化往往来自于人们的随心所欲。尝试不同的解决方案来解决当前的痛点,每个框架都在向对方学习。

一个大主题是精简和简化。把事情从运行时移到编译时是这些主题之一,激发了 "React forget",这是一个有可能消除缓存需求的功能。

它们的共同点是解决了文件的互动部分。正如我们所看到的,这是一个具有挑战性的方面,要以一种容易扩展的方式来解决。

同时,我们看到了纯客户端渲染的代价。当加载一个页面时,那个空白的白屏需要更长的时间。

在移动设备和网络上,这就有点像一场灾难。

于许多网站来说,快速移动、不降低性能成为主要的竞争优势。

我们迈出了一步,正在探索通过在服务器上先渲染内容来加快渲染速度的方法(才发现这是一个权衡的结果)。

这一最初的后退为许多元框架和html优先前端框架的新浪潮点燃了道路。

新一波的Javascript Web 框架

受PHP的启发,Next进一步简化了创建静态页面推到CDN的过程。它还解决了React应用中使用SSR的麻烦部分。

它带来了一些人们非常想要的关于结构化应用的意见,使用基于文件的路由。还有一堆其他的好功能。

从那时起,一波又一波的元框架应运而生。对于Vue,我们在Nuxt中有一个类似的框架。slvelte的slveltekit,以及即将到来的SolidStart。

这些都是服务器优先的,旨在整合web框架的所有部分和人体工程学。不仅仅是长期以来备受关注的互动元素。是关于改进用户体验和开发人员体验,而不是以一种方式交换另一种。

MPA的反击

多页面架构从服务器上提供HTML,其中导航是全页面刷新。

快速启动对许多网站来说是至关重要的,特别是那些在登录之外的网站。它直接关系到搜索排名和跳出率等事情。

对于许多互动性不强的网站和应用程序来说,使用像React这样的客户端渲染库是过犹不及。

对许多人来说,这意味着翻转剧本。以HTML为先,而不是以Javascript为先,以MPA取代SPA,并默认为零Javascript。

像Marko、Astro、Fresh、Rocket和Enhance等框架都采用了这种方法。

与一些元框架相比,路由器停留在服务器上,而不是让客户端的路由器在第一次加载后接管。

在Javascript生态系统中,这是对Node之后不久的基于服务器的模板制作的一种回溯。这一轮的MPA与前几代不同。碎片"是以基于组件的模式编写的,通常使用岛屿模式。前端和后端代码使用相同的语言。常常在同一个文件中共存。

这消除了在添加一些交互性时,在前端和后端构造不同的重复模板代码的问题。

渐进式增强的回归

Remix在React生态系统中带来了渐进式增强的回归。

从技术角度来看,Remix是React Router的编译器,和其他新兴的元框架一样,是一个边缘兼容的运行时。

它通过嵌套布局和数据获取API,解决了Facebook通过Relay大规模解决的相同挑战。

这允许早期的代码和数据的并行获取。使用Suspense的 "边渲染边获取 "模式的一个很好的先决条件。

对渐进式增强的强调意味着它的API是基于Web标准的,data mutation story 是基于HTML表单的。

而不是通过连接事件处理程序来进行必要的获取请求。渲染表单,将数据提交给在服务器上处理它们的action functions(通常在同一个文件中)。受到PHP的启发。

与Next类似,应用程序可以缩小规模,像传统的服务器渲染的MPA一样在没有Javascript的情况下工作,或者按每页的规模扩大到交互式React应用程序。

Remix还提供了许多API和模式来处理诸如乐观的UI更新、处理竞争条件和优雅的退化,这些都是你希望一个专注于终端用户体验的深思熟虑的框架所提供的。

hybrid 未来

不要与Quic协议相混淆。Qwik这个框架是关于最小化不必要的Javascript。

虽然它的API看起来像React,但它的方法与其他元框架不同,它专注于hydration process

就像你可以暂停一个虚拟机并将其移到不同的物理机上一样。Qwik将这一理念应用于服务器和浏览器之间的工作。

它的 "可恢复" hydration 的想法意味着你可以在服务器上启动一些东西,然后在客户端恢复,而不需要任何返工。

这与 partial hydration作用相反,当 hydration work 发生时,[partial hydration] 会移动,Qwik试图在第一时间避免这样做。

这是一套有趣的想法,它利用了服务器和客户端紧密结合的力量,允许这种动态捆绑和服务。

这些概念开始模糊了MPA和SPA之间的界限,一个应用程序可以从MPA开始,动态地过渡到SPA。

总结

关于什么是最好的框架、架构或模式,没有一个普遍的答案,在这篇文章中提到的以及我们没有提到的无数其他框架、架构或模式。

这总是对特定指标的权衡。要知道如何权衡取决于你正在建造的东西。你的用户是谁,以及他们的使用模式。以及围绕关键用户体验的任何其他要求(如性能预算)的设定。

对我们大多数人来说,真相会介于两者之间。新一波框架和创新的伟大之处在于,它们提供了根据需要扩大或缩小规模的杠杆。

对于那些刚进入这个行业的人和那些有经验的人来说,投资于基本面总是一个好的选择。

框架的演变慢慢地将原生 web 推向了更远的地方,消除了以前对框架的需求,以平滑其粗糙的边缘,并减轻了以前的权衡--使我们能够越来越多地采用其原生功能。

编辑中可能存在的bug没法实时知道,事后为了解决这些bug,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

来源:https://frontendmastery.com/p...

交流

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。


王大冶
68.1k 声望105k 粉丝