前端框架:解决方案还是臃肿的问题?

已发表: 2022-03-11

现代前端框架要求您在尝试在浏览器上查看之前下载开发环境、完成依赖项并编译代码。 这是一件好事吗? 问题是我们正在构建更复杂的网站,还是框架本身就很复杂,引入了不必要的复杂程度?

自 90 年代以来,今天的 Web 开发已经发展了很多。 我们能够创造出非常接近任何原生应用程序的完整体验,并且开发过程也发生了变化。 成为前端 Web 开发人员只需打开记事本、输入几行代码、在浏览器上检查并将其上传到 FTP 文件夹的日子已经一去不复返了。

过去的前端 Web 开发

我必须首先说明一个显而易见的事实:世界不像 10 年前那样。 (震惊,我知道。)唯一不变的就是变化。 过去,我们的浏览器很少,但存在很多兼容性问题。 今天,您很少看到“在 Chrome 43.4.1 上观看效果最佳”之类的内容,但在当时,这很常见。 我们现在有更多的浏览器,但兼容性问题更少。 为什么? 因为jQuery 。 jQuery 满足了拥有一个标准的通用库的需求,它允许您编写操作 DOM 的 JavaScript 代码,而无需担心它如何在每个浏览器和每个浏览器的每个版本上运行——这是 2000 年代真正的噩梦.

现代浏览器可以将 DOM 作为标准来操作,因此近年来对此类库的需求已大大减少。 不再需要jQuery,但我们仍然可以找到许多非常有用的插件依赖于它。 换句话说,Web 框架可能不是必需的,但它们仍然足够有用,可以流行和广泛使用。 这是大多数流行的 Web 框架的共同特征,从 React、Angular、Vue 和 Ember 到像 Bootstrap 这样的样式和格式化模型。

为什么人们使用框架

在 Web 开发中就像在生活中一样,拥有一个快速的解决方案总是很方便的。 你以前用 JavaScript 做过路由器吗? 当你可以 npm-install 一个前端框架来克服这个问题时,为什么还要经历痛苦的​​学习过程呢? 当客户想要昨天完成的事情,或者您从其他开发人员那里继承为特定框架设计的代码,或者如果您正在与已经使用给定框架的团队集成时,时间就是一种奢侈。 让我们面对现实吧——框架的存在是有原因的。 如果对他们没有好处,就没有人会使用它们。

那么使用 Web 开发框架有哪些好处和独特的属性呢?

时间就是金钱。 当你在开发一个项目时,客户并不关心你使用哪个框架——实际上,可能甚至不知道你使用的是什么——他们只关心得到结果,而且越快越好。 已建立的框架可让您从一开始就立即创建进度感,这是客户从第一天起就渴望的。此外,您开发得越快,您赚的钱就越多,因为框架腾出的时间可以重定向到承担更多项目。

这一切都与社区有关。 在选择框架时,这是非常重要的一点——当你遇到问题时,谁来帮助你? 你和我都知道它会在某个时候发生。 您将到达需要做一些框架不打算做的事情的地方,或者框架从未设计为让您访问的地方,因此有一个支持您的社区是必不可少的。 开发——尤其是自由职业者——可能很难,因为你沉浸在一个虚拟世界中,如果你是团队中唯一的前端 Web 开发人员,这意味着你是唯一一个有经验和专业知识的人可以找到一个解决方案。 但是,如果您使用的前端框架有可靠的支持,那么在世界的另一端就会有人面临同样的问题并且可能能够帮助您。

标准是美丽的。 你有没有注意到,当你查看自己的一段旧代码时,你可以很容易地浏览它? 或者至少,比其他人编写的一段代码更容易? 你以某种方式思考,你有自己的方式来命名事物和组织代码。 这是一个标准。 我们都追随他们,即使他们只是为了我们自己。 我们倾向于在早餐时吃类似的东西,在特定的时间醒来,每天把钥匙放在同一个地方。 事实上,如果我们每天都改变我们的日常生活,那么仅仅因为弄清楚如何做事的开销,生活就会变得更加艰难。 曾经因为将钥匙放在与平常不同的地方而丢失了钥匙吗? 标准让生活更轻松。 当作为团队或开发人员社区的一部分工作时,他们变得绝对不可或缺。

框架从您安装它们的那一刻起就提供了一个标准,指导您以特定的方式思考和编码。 您无需花时间与您的团队一起制定标准; 您可以按照框架中的操作方式进行操作。 这使得一起工作更容易。 当您知道函数必须在某个文件中时,查找函数会更容易,因为它是为在 SPA 中添加路由而构建的,并且在您的框架中,所有路由都放在具有该名称的文件中。 如果你有这种标准化水平,具有不同技能水平的人可以一起工作,因为虽然高级编码人员知道为什么要这样做,但即使是初级开发人员也可以遵循标准本身。

当框架失败时

几年前,如果说“我不使用框架——我看不出它们有什么真正的好处”之类的话,就会把拿着火把和干草叉的人带到你家门口。 但是今天,越来越多的人在问自己,“我为什么要使用框架? 我真的需要它们吗? 没有它们,编码有那么难吗?”

我当然是其中之一——我从来都不是任何特定框架的粉丝,而且在我的整个职业生涯中,我一直在没有它们的情况下进行编码。 如果我在这件事上可以选择,我的选择总是,“不,谢谢。” 多年来,我一直在使用 JavaScript 进行开发,在此之前,我一直在使用 ActionScript。 当大多数人已经认为它已死时,我正在使用 Flash 进行编码。 (我知道,我知道……但我做了很多动画,而纯 HTML 的动画很难。)因此,如果您是众多从未考虑过没有框架进行编码的人之一,那么让我向您展示一些您可能会这样做的原因挣扎。

“一刀切”是谎言。 你能想象编写一个软件来完成你在职业生涯中所做的一切吗? 这是 Web 开发框架的主要问题之一。 您的项目有非常具体的需求,我们倾向于通过添加库、插件或附加组件来扩展框架的范围来解决这些需求。 没有框架能 100% 提供你需要的东西,也没有框架是 100% 由你会发现有用的东西组成的。

有太多不使用的代码会导致网站的加载时间滞后,这对于每个额外的用户来说变得更加重要。 另一个问题是“一刀切”的心态会导致代码效率低下。 举个例子, $('sku-product').html('SKU 909090'); , 这是 jQuery 代码,我们都知道最终会被翻译成类似document.getElementById('sku-product').innerHTML = 'SKU 909090'; .

单行上的这种差异似乎并不重要,但更改页面特定元素的内容正是 React 的优点。 现在,React 完成了创建 DOM 表示并分析您尝试呈现的内容的差异的过程。 从一开始就定位您想要更改的内容不是更容易吗?

你走过的那团杂草正在长出荆棘。 你有没有遇到过这样的情况,你正在使用你的框架并试图向它添加一个库,只是意识到你需要的库版本不能很好地与你正在使用的框架版本一起工作? 有时,让两段代码一起工作比自己编写代码需要更多的努力。 而且由于您使用的框架和库通常构建在其他框架和库上,这些框架和库可能隐藏着您甚至无法预料的不兼容问题,因此问题可能会呈指数级增长,达到无法管理的程度希望项目继续发展。

跟上琼斯是一回事。 曾经在 AngularJS 中工作过一个项目,却发现您需要一些在 Angular 4 发布之前才出现的东西? 你甚至知道 Angular 5 已经发布了吗? 这是另一个大问题。 即使你坚持使用单一的前端框架,当一个新的主要版本发生时,事情可能会发生很大变化,以至于你努力制作的代码甚至无法在新版本上运行。 这可能会导致任何事情,从需要对大量文件进行的烦人的小改动到完全重写代码。

跟上框架的最新版本具有挑战性,但同样,当更新完全停止并且无法跟上其余技术时,其他框架会受到影响。 2010 年,AngularJS 和 Backbone 都首次发布。 今天,Angular 已经发布了它的第五个主要版本,而 Backbone 完全不在聚光灯下。 七年似乎很长。 如果您建立网站,它们的美学和功能可能已经完全改变。 如果你正在构建一个应用程序,押注错误的框架可能会使公司在以后需要重写时陷入艰难且昂贵的境地。

当你只有一把锤子时,一切看起来都像钉子。 如果您经常使用 Web 开发框架,那么您可能遇到过这种情况,其中单个代码库定义了您将来使用的代码的形状,即使它只是外围相关的。 假设您要构建一个像 YouTube 这样的平台,并且您想使用 Framework X。可能有一点,即使在这个时代听起来很荒谬,您还是决定使用 Flash 来制作视频,因为这就是结果内置于框架中。

框架有意见,而且很强大; 例如,React 强制您以特定方式使用 JSX。 您可以在任何地方看到以这种方式使用的代码。 有替代方案吗? 是的。 但谁使用它? 这并不总是一件坏事,但如果你需要执行复杂的动画,你可能只需要一个动画框架而不是整个 React。 我见过人们做一些疯狂的事情,比如将 jQuery 添加到页面只是为了将节点附加到元素,这可以在 vanilla JS 中通过document.getElementById('id_of_node').appendChild(node);完成。 .

Eval 是邪恶的,但.innerHTML是马基雅维利式的

我想花时间单独探讨这一点,因为我认为这是更多人不编写没有框架的代码的原因之一。 当您看到大多数代码在尝试向 DOM 添加内容时是如何工作的时,您会发现.innerHTML属性注入了一堆 HTML。 我们似乎都同意eval不利于运行 JavaScript 代码,但我想在这里将.innerHTML放在聚光灯下。 当您将 HTML 代码作为纯字符串注入时,您可能会丢失对您创建的任何节点的任何引用。 确实,您可以通过使用getElementsByClassName或为它们分配一个id来取回它们,但这不太实际。 当尝试更改其中一个节点的值时,您会发现自己又重新渲染了整个 HTML。

当您开始编码时,这很好。 无需太多经验,您就可以轻松做出很多简单的事情。 问题出现在现代网站的复杂性上,它往往更像应用程序——这意味着我们需要不断地改变节点的值,如果你通过重新连接整个结构来做到这一点,这是一项高成本的操作通过.innerHTML 。 React 通过影子 DOM 有效地解决了这个问题,而 Angular 通过使用绑定作为修改页面上显示的值的简单方法来解决这个问题。 但是,通过跟踪您创建的节点并保存将在变量中重用或更新的节点,也可以相当容易地解决它。 通常还有其他原因远离.innerHTML

关于没有框架的编码的最大神话

时间就是金钱。 是的,我把这个概念从早些时候带回来了。 很多人觉得,如果他们停止使用流行的 Web 框架,我们将立即转向 90 年代的互联网,当时<marquee>是每个人最喜欢的标签,Geocities 网站上的旋转 GIF 既时髦又前卫,Alta Vista 是首选。用于网络搜索,命中计数器无处不在。

使用 Web 框架,您的第一行代码似乎可以节省很多时间,但在某些时候,收益会变成损失。 你花时间阅读如何让框架做它不适合做的事情,如何集成库并让它们与框架配合得很好,并发现你在遵循框架标准的情况下构建的代码是行不通的完全可以工作,现在你需要重写它。 当你在没有框架的情况下做事时,你开始的速度会慢一些,但你会稳步前进。 最后,这一切都是关于你想要简单的部分。 总时间不会有太大区别。

我的代码会比长城还长。 没有框架的写作就像买电影而不是订阅流媒体服务。 您无法即时访问数百部您想观看的电影,但您也不必花钱购买数千部您甚至从未考虑从商店下载的电影。 你可以只写你需要的。

中间人有用吗? 当然。 但这通常不是必需的。 您编写的每一行代码都具有更多意义,因为您无需适应框架的要求。 感觉就像你在用纯 JavaScript 编写更多代码,因为创建 DOM 元素的方式需要几行代码来创建一个元素,将它附加到 DOM,并且可能添加一个样式类,而不是调用一行JSX 中的代码。 但是,如果您使用 jQuery 或 React 之类的库比较代码,vanilla JS 的长度可能非常相似。 有时它更长,但有时它也更短。

没有必要重新发明轮子。 计算机科学教授的口头禅无处不在。 这是真的——它只是不必专门指框架。 例如,发送 Ajax 请求以加载或保存数据是几乎每个 Web 应用程序的要求,但没有框架并不意味着您每次都需要重新编写代码。 您可以创建自己的库或代码库,也可以从其他人那里提取代码。 它越小,就越容易根据需要进行修改或调整,因此当您需要某个项目的特定内容时,它会派上用场。 修改 100-200 行代码比浏览第三方库或框架可能包含的大量文件更容易。

它只适用于小型项目。 这是一个非常普遍的神话,但根本不是真的。 目前,我正在开发一个完整的系统,以便在一个地方在线管理公司的所有方面,包括一个类似于 Google Drive 的模块。 无论是否使用框架,我都会经历非常相似的步骤并遇到非常相似的问题。 差异可以忽略不计。 但是,如果没有框架,我的整个代码会更小且更易于管理。

我要证据

好的。 让我们停止谈论理论,跳到一个现实世界的例子。 几天前,我需要展示带有商店徽标的品牌列表。 最初的代码使用 jQuery,但它有一个问题,当在 Mozilla 中加载时,它会为尚未上传徽标的品牌显示一个损坏的图像图标。 我们不能因为 X 公司还没有完成他们的工作而让商店看起来未完成,但该功能需要上线。

以下代码使用.innerHTML的 jQuery 等效项:

 var list_brand_names = ['amazon', 'apple', 'nokia']; var img_out = ''; for (i=0;i<list_brand_names.length;i++) { var brandName = list_brand_names[i].toLowerCase(); img_out += "<a href='/pages/" + brandName + "'><img src='images/" + brandName + "' /></a>"; } jQuery("#brand-images").html(img_out);

没有深入探讨 jQuery 的优缺点,这里的问题是我们没有对我们创建的图像的任何引用。 虽然有些解决方案不涉及更改代码,但让我们借此机会看看如何在没有任何库的情况下完成它:

 var brands = ['amazon', 'apple', 'nokia']; var brand_images = document.getElementById("brand-images"); for (var iBrand = 0; iBrand < brands.length; iBrand++) { var link = document.createElement('a'); link.setAttribute('href', '/pages/' + brands[iBrand]); link.style.display = 'none'; brand_images.appendChild(link); var image = new Image(); image.src = "images/" + brands[iBrand] + "png"; image.onload = function(){ this.parentNode.style.display = ''; } link.appendChild(image); }

原始的 jQuery 代码长达六行,而 vanilla JS 解决方案则需要十二行。 为了解决这个问题,隐藏每个图像直到它被加载,需要两倍的时间来编码。 所以让我们看看替代方案。 它也可以在jQuery中解决吗? 看看这个:

 img_out += "<a href='/pages/" + brandName + "'><img src='images/" + brandName + "' onload="showImage(this)"/></a>"; function showImage(image){ image.parentNode.style.display = ""; }

加上几行代码,现在 jQuery 和 vanilla 之间只有三行区别,但是在 jQuery 上,您可以看到img_out行很快变得非常复杂,到了需要暂停的地步仔细想想你在做什么。 直接用节点函数来编码DOM,添加属性、函数等可能会比较冗长,但是每一行都有更清晰、更准确的含义,方便以后阅读和维护。

让我们看一下 React:

 function BrandLink(props) { var url = "images/" + props.brand + ".png"; return (<a href="{props.brand}"><img src={url}/></a>); } class Brands extends React.Component { constructor() { super(); this.state = {brands: ['amazon', 'apple', 'nokia']}; } render() { const links = this.state.brands.map((step, move) => { return (<BrandLink brand={step} key={step}/>); }); return (<div className="brands">{links}</div>); } } ReactDOM.render(<Brands />, document.getElementById("root"));

这个版本显然是次优的。 代码并不比原版中的短,我们甚至还没有达到解决问题和隐藏链接的地步,直到其中的图像加载完毕。

对于每个示例,结果都会有所不同。 有时,jQuery 会更短。 有时,React 会赢。 有时香草 JS 可能比它们都短。 无论如何,这里的目标不是证明一个在本质上优于另一个,而是证明在代码长度方面使用 vanilla JS 和使用框架之间没有显着差异。

结论

就像任何现实生活中的问题一样,没有什么是非黑即白的。 没有 Web 开发框架的编码可能是您的某些项目的最佳解决方案,而在其他项目中则是一场噩梦。 就像每个工具一样,关键不仅在于学习如何使用它,还在于学习何时使用它,以及使用它的优点和缺点可能是什么。 使用纯 JavaScript 进行编码就像使用任何框架一样 — 掌握它需要时间才能让您感到自在使用它。

但关键的区别,至少对我来说,是框架来来去去,即使一个框架流行了很长时间,它也可以从一个版本到另一个版本发生巨大的变化。 纯 JavaScript 将是一个更长的选择,直到它完全不再相关并且出现了一些其他语言。 即便如此,与将给定框架迁移到另一种语言相比,您可以直接从一种语言迁移到另一种语言的概念和策略也会更多。 就单个项目而言,时间和精力大致相当,知识折旧的减少以及您可以为下一个挑战学习的经验是需要考虑的非常重要的因素。

相关:微前端的优势和优势