我希望了解一下这些框架的共性和差异,Web 平台作为一种更精简的选择,能提供什么,以及它是否足够。我的目标并非要抨击这些框架,而是要了解成本和效益,找出有没有其他选择,甚至当我们决定采用框架时,我们也能从中吸取教训。
成都创新互联公司云计算的互联网服务提供商,拥有超过13年的服务器租用、成都二枢服务器租用托管、云服务器、虚拟主机、网站系统开发经验,已先后获得国家工业和信息化部颁发的互联网数据中心业务许可证。专业提供云主机、虚拟主机、域名注册、VPS主机、云服务器、香港云服务器、免备案服务器等。
在本系列文章的第一部分中,我将深入探讨一些框架的共性技术特性,并介绍几种不同的框架是怎样实现这些特性的。我还要看一下使用这些框架的成本。
我选取四种架构进行研究。React 是当今的主流框架,还有三个较新的竞争者,它们声称自己的工作方式与 React 不同。
总结一下这些框架对其差异化的说法:
框架自身也提及了诸如声明性、反应性和虚拟 DOM 等词。让我们深入了解它们的含义。
声明性编程是一种范式,在这种范式中,逻辑被定义,而没有指定控制流。我们描述需要的结果是什么,而不是我们会采取什么步骤。
在 2010 年左右,声明性框架的早期,DOM 的 API 更加简单,更加冗长。而使用命令式的 JavaScript 编写 Web 应用程序则需要大量的模板代码。这时,“模型 - 视图 - 视图模型”(model-view-viewmodel,MVVM)的概念开始盛行,当时具有划时代意义的 Knockout 和 AngularJS 框架,提供了一个 JavaScript 声明层,在库内处理这种复杂性。
今天,MVVM 并不是一个广泛使用的术语,它在某种程度上是旧术语“数据绑定”的变种。
数据绑定是一种声明性的方式,用来表示数据如何在模型和用户界面之间同步。所有流行的 UI 框架都提供了某种形式的数据绑定,它们的教程都以数据绑定的例子开始。
以下是 JSX(SolidJS 和 React)中的数据绑定:
function HelloWorld() {
const name = "Solid or React";
return (
Hello {name}!
)
}
Lit 中的数据绑定:
class HelloWorld extends LitElement {
@property()
name = 'lit';
render() {
return html`Hello ${this.name}!
`;
}
}
Svelte 中的数据绑定:
Hello {name}!
反应性是一种声明性的方式来表达更改的传播。
如果我们能够用一种声明的方式来表示数据绑定,那么我们就必须要有一个使框架能够传播更改的高效方法。
如果框架为数据绑定提供了声明性的接口,并且能够实现反应性,那么就必须提供一些方法来表达一些传统意义上的逻辑,这些逻辑是以命令的方式写的。逻辑的基本构件是 “if” 和 “for”,而所有的主流框架都提供了这些构件的一些表达。
(1) 条件句
除了绑定数字和字符串等基本数据外,每个框架都提供了一个“条件”原语。在 React 中,它看起来如下所示:
const [hasError, setHasError] = useState(false);
return hasError ? : null;
…
setHasError(true);
SolidJS 提供了内置的条件组件。
Svelte 提供了 #if 指令:
{#if state.error}
{/if}
在 Lit 中,你将在 render 函数中使用显式三元运算:
render() {
return this.error ? html``: null;
}
(2) 列表
另一个常见的框架基元是列表处理。列表是用户界面的一个关键部分——如联系人列表、通知等——要想高效工作,就必须有反应性,而不是在一个数据项发生变化时,对整个列表进行更新。
在 React 中,列表处理看起来像这样:
contacts.map((contact, index) =>
React 使用特殊的 key 属性来区分列表项,它确保整个列表不会在每次渲染时被替换。
在 SolidJS 中,使用了 for 和 index 内置元素:
{contact =>{contact.name}}
在内部,SolidJS 将自身的存储与 for 和 index 相结合,以确定在项目发生个更改时要更新哪些元素。它比 React 更清晰,使我们能够避免虚拟 DOM 的复杂性。
Svelte 使用 each 指令,该指令根据其更新器被转译:
{#each contacts as contact}
{contact.name}
{/each}
Lit 提供了一个 repeat 函数,它的工作原理类似于 React 的基于键的列表映射:
repeat(contacts, contact => contact.id,
(contact, index) => html`${contact.name}`
有一件事超出了本文的范围,那就是不同框架中的组件模型,以及如何使用自定义 HTML 元素来处理它。
注意:这是一个很大的主题,我想在以后的文章里讨论这个主题,因为这个主题会让这篇文章变得太长。
框架提供了声明性的数据绑定、控制流原语(条件和列表),以及传播更改的反应性机制。它们还提供了其他重要的东西,比如重用组件的方法,但这就是另一篇文章的主题了。
框架有用吗?是的。它们带给了我们所有这些方便的特性。但这是一个正确的问题吗?使用框架需要付出一定的成本。让我们来看一下这些成本。
在查看包大小时,我更愿意看到非 Gzip 的缩减大小。这个尺寸与 JavaScript 的 CPU 开销有很大关系:
现在看来,在保持包大小上,现在的框架要优于 React。虚拟 DOM 要求使用很多 JavaScript。
不知何故,我们习惯了“构建” Web 应用。如果不设置 Node.js 和 Webpack 这样的捆绑器,不处理 Babel-TypeScript 启动包中最近的一些配置更改,以及所有这些事情,就不可能启动一个前端项目。
越是有表达力的框架,包大小就会变得更小,但构建工具和转译时间的负担就越大。
Svelte 宣称,虚拟 DOM 完全是一种开销。我同意,但是可能像 Svelte 和 SolidJS 这样的“构建”以及像 Lit 这样的自定义客户端模板引擎都只是单纯的开销吗?
在构建和转译过程中,需要付出的成本也是不同的。
我们在使用和调试 Web 应用程序时,所见到的代码和我们所编写的完全不一样。我们现在依靠同样品质的调试工具,逆向设计出一个站点,并把它和我们自己的代码中的 bug 相关联。
在 React 中,调用栈从来不是“你的”事情——React 会为你处理调度。这一特性在没有 bug 的时候非常好用。但是,如果你试图找出无限循环重现的原因,你将会陷入痛苦的境地。
在 Svelte 中,库本身的包大小很小,但你要传输和调试一大堆神秘的生成代码,这些代码是 Svelte 对反应性的实现,根据你的应用需求定制。
Lit 并不需要进行大量的构建,但是要想有效地进行调试,你就必须熟悉其模板引擎。这也许是我对框架持怀疑态度的最大原因。
当你寻求自定义的声明式解决方案时,你将面对更加困难的命令调试。本文中的示例采用了 TypeScript 来对 API 进行规范,但是该代码本身并不需要转译。
在本文中,我讨论了四个框架,但是还有许多其他的框架,多得数不清(AngularJS、Ember.js 和 Vue.js,仅举几例)。你能指望框架、它的开发者、它的思想和它的生态系统在开发过程中为你工作?
除了修补自己的 bug 之外,还有一个更让人沮丧的事情,就是必须为框架的错误找到变通方法。而且,还有一个更加令人沮丧的事情,那就是在没有修改你的代码的情况下,将框架升级为新的版本,会出现 bug。
诚然,浏览器中也有这样的问题,但是这种问题一旦出现,就会影响到所有人,而且在大多数情况下,修复或者发布一个解决方案,都是迫在眉睫的。此外,本文提到的大部分模式都建立在成熟的 Web 平台 API 之上,并不一定都需要采用尖端技术。
我们对框架所要处理的核心问题有了更深刻的理解,并且着重于数据绑定、反应性、条件和列表。我们也对成本进行了讨论。
在本系列的第二部分中,我们将会了解到,在没有框架的情况下,我们是怎样处理这些问题的,以及我们可以从中学习到什么。敬请关注!
原文链接:https://www.smashingmagazine.com/2022/01/web-frameworks-guide-part1/
标题名称:Web框架能解决什么问题?
文章链接:http://www.shufengxianlan.com/qtweb/news36/544286.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联