编写可维护的 javascript-JavaScript框架发展的四个时代你经历了几个阶段?

出品| CSDN(ID:CSDNnews)

早在 2012 年,我就开始使用 JavaScript 进行编码。

我曾经为一家本地企业从头到尾开发了一个 PHP 应用程序,一个简单的 CMS 网站。 后来他们决定重写它,减少一些功能。 这个项目的负责人希望我使用.NET来开发,部分原因是他更了解这项技术,同时他也希望让这个项目成为一个类似的原生应用程序——减少页面加载时间。 经过一些研究和原型设计后,我说服他用 Web 方法做同样的事情,就在那时,一个全新的 JS 框架出现了。

我选择的第一个框架实际上是Angular1。 当时我基于FuelPHP前端开发了一个相当大的应用程序。 从功能上讲,每次重新渲染子路由/出口时,路由器都会闪烁,这是我们在开发过程中没有考虑到的意外情况。 后来有人向我推荐了Ruby on Rails+Ember的方案。 尝试之后,我觉得效果非常好。 我喜欢框架和构建它们的社区的哲学。

从那时起,很多事情都发生了变化,出现了许多新的框架,旧的框架已经退役。 使用 JavaScript 在浏览器中构建应用程序的想法已经从少数开发人员的尝试发展成为后端世界的标准实践。 随着开发人员构建的基础设施发生变化,出现了许多新的可能性。

这段时间,很多开发者的想法都深受困扰和矛盾。 我想很多在后端领域工作了一段时间的人可能都有过这样的经历,郁闷于使用哪个JavaScript框架,如何编写CSS,是否使用函数式编程还是面向对象编程,如何最好地管理状态,构建最灵活、最快等的系统或工具。

回想起来,我发现很有趣的是,我们经常为小错误而争论,而忽略了更有意义的事情,这实际上是“事后诸葛亮”。 所以我想做一个回顾,总结一下过去这几年、六年的JavaScript发展,看看我们走了多远。 我认为我们可以大致将其分为四个主要时代:

前世

第一代框架

以组件为中心的视口

全栈框架(←这是我们目前所处的位置)

每个时代都有其标志性特征和亟待解决的矛盾。 每个时代也给了我们不同的经验和教训,最终让我们进步。

关于 JavaScript 开发,争论一直持续到明天:网站是否臃肿? 普通网站真的需要用React写吗? 我们是否应该使用 JavaScript? 我认为我们不会在这里听到关于未来的消息,但最终我怀疑我们可能会再次发现我们正在互相交谈而没有关注更广泛和有意义的技术。 而且,回顾过去,其实其中的一些观点也可以帮助我们更好地走向未来。

编写可维护的js_编写可维护的 javascript

前世

JavaScript 首次发布于 1995 年。正如我之前提到的,我在 2012 年开始编写 JS,距离 JavaScript 诞生已经快 20 年了,也就是我所说的“第一个框架”时代的开始。 你可以想象,这个时代可以分为许多子时代,每个子时代都有自己的模式、库、重构工具等。

也就是说,我不能写我自己没有经历过的事情。 当我开始编写后端应用程序时,新一代框架才刚刚开始成熟,例如 Angular.js、Ember.js、Backbone 等。

在此之前,jQuery 和 MooTools 等库是最先进的。 这些库在当时非常重要,它们有助于消除 JavaScript 表单的浏览器实现之间的差异,这一点非常重要。 例如,IE对storm的实现形式与Netscape(网景浏览器)完全不同,其形式分别是风暴冒泡和风暴捕获。 这就是为什么我们的标准今天最终实现了这两种方法,但在此之前,您需要使用库来编译可以在两种浏览器上使用的代码。 该库主要用于制作大型、独立的用户界面小部件。 大多数应用程序的业务逻辑始终通过表单和标准 HTTP 请求,即在服务器上呈现 HTML 并将其提供给客户端。

在当今时代,没有太多构建工具可言(至少据我所知)。 当时的 JavaScript 没有模块(至少没有标准模块),所以没有办法导出代码。 一切都是全球性的,要把这种事情组织好是非常困难的。

在这些情况下,可以理解的是,JS 通常被视为一种要使用的语言,而不是可以用它编写的完整应用程序。 当时,开发人员最常见的事情就是使用 jQuery 并为一些 UI 小部件编写一些脚本。 随着时间的推移以及XHR的引入和流行,开发人员开始将部分UI流程放在页面中,特别是对于需要客户端和服务器之间多次来回交互的复杂流程。 但是,应用程序的大部分内容仍保留在服务器上。

这与联通应用刚出现时的情况形成鲜明对比。 从一开始,iOS和Android上的中国联通应用程序就是一个用Objective-C和Java等中级语言编写的完整应用程序。 据悉,它们完全由API驱动——所有UI逻辑都存在于设备上,与服务器的通信纯粹以数据的形式。 这带来了更好的用户体验,也带来了联通应用的爆燃,直接引发了我们明天对联通设备和Web网络更好的争论。

起初,许多人认为用 JavaScript 完成这一切是荒谬的。 但随着时间的推移,这些应用程序开始看起来更加雄心勃勃。 很多社交平台都减少了聊天、DM等实时功能。 Gmail和GoogleDocs已经验证浏览器也能实现与桌面相同的用户体验。 越来越多的公司已经开始提供Web应用程序开发服务,因为在他们的Web中,似乎到处都可以工作,而且更容易全年维护。 这导致了整个网络行业的发展。

显然,JS现在可以用来编译更复杂的应用程序。 不过,在当时的环境下,要实现这一点还是有些困难的,因为当时的 JavaScript 还不具备明天的所有功能。 就像我说的,一切都是全局的,您通常需要自动下载每个外部库并将其添加到静态资产文件夹中。 那时还没有 NPM,模块也不存在,JS 也不具备明天的一半功能。 在大多数情况下,每个应用程序都需要定制,每个页面都有不同的插件设置,每个插件都有不同的系统来管理状态和渲染更新。 为了解决这类问题,最早的JavaScript框架出现了。

编写可维护的js_编写可维护的 javascript

第一代框架

在 2000 年代末和 2010 年代初,第一个专门用于编写完整客户端应用程序的 JS 框架开始出现。 这个时代的一些著名框架是:

事实上,个人圈子里还有很多其他或者更著名的框架。 然而,以上是我记得的,我经常使用它们来进行原型设计或改进。

这是第一代框架,即将打开未知领域的大门。 一方面,这个框架试图做的事情太过超前,以至于很多人认为他们不会真正成功。 有很多反对者认为单页 JS 应用程序(SPA)从根本上来说是糟糕的,但随着时间的推移,这些批评者在很多方面都被证明是正确的,例如,客户端渲染意味着手动程序不能轻易地抓取这些页面,用户甚至需要等待几秒钟才能开始绘制应用程序草图。 很多这样的应用程序都是噩梦,如果你关闭 JavaScript,它们根本无法运行。

另一方面,我们没有用 JS 构建成熟应用程序的经验,因此许多开发人员对最佳方法有很多不同的意见。 大多数框架都试图模仿其他平台上的流行做法,因此几乎所有框架最终都以“Model-View-*”的迭代方法告终,例如Model-View-Controller、Model-View-Producer、Model-View-ViewModel等等。 从长远来看,其中一些问题确实得到了解决,而且解决方案往往并不直观,但应用过程却变得越来越复杂。

这也是我们真正开始尝试如何编译 JavaScript 应用程序的时候。

Node.js 于 2009 年发布,NPM 于 2010 年发布,将包的概念引入(服务器端)JavaScript。 CommonJS 和 AMD 竞争如何定义最好的 JS 模块,而 Grunt、Gulp 和 Broccoli 等构建工具则竞争如何将这些模块组合成可交付的最终产品。

在大多数情况下,这些都是非常通用的类似任务运行器的工具,它们确实可以构建任何东西,只是恰好与 HTML、CSS/SASS/LESS 等结合起来,并为基于 JavaScript 的 Web 开发了很多产品。

从这个时代,我们学到了很多,也积累了宝贵的经验,包括:

总的来说,这个时代是硕果累累的。 尽管存在这一缺点,但随着应用程序复杂性的降低,将客户端与 API 解耦的好处是巨大的,并且在许多情况下,可以显着改善用户体验。 如果情况不同,这个时代可能会继续下去,我们可能还会重复MV*的风格直到明天。

但随后,一颗“小行星”突然出现,打破了现有范式,引发了一场小型的灭绝风暴,并将我们推入了下一个时代——这颗“小行星”被命名为React。

编写可维护的js_编写可维护的 javascript

以组件为中心的视口

我不觉得 React 发明了组件,但说实话,我不太确定它们最初来自哪里。 我知道现有技术至少可以追溯到 .NET 中的 XAML,那时 Web 组件开始作为规范传播。

如今每个主要框架都使用组件。 事后看来,它的流行也是完全合理的——扩展 HTML、减少常年状态、将 JS 业务逻辑直接绑定到模板(无论是 JSX、Handlebars 还是 Directive)。 基于组件的应用程序消除了完成工作所需的大部分具体概念,但极大地简化了代码生命周期。 一切都与组件的生命周期而不是应用程序的生命周期相关,这意味着作为开发人员,您需要考虑的事情要少得多。

然而,当时还有另一个变化:该框架开始标榜自己是一个“视口”,而不是一个完整的框架。 他们不再解决后端应用程序所需的所有问题,而只专注于解决渲染问题,其他问题如路由、API通信和状态管理等都由用户自己决定。 这个时代著名的框架包括:

事实上,还有很多很多其他框架。 现在回想起来,我认为这是二代框架中比较流行的一个框架,因为它主要做了两件事:

它极大地缩小了范围。 这个框架的核心并不是试图解决所有后端问题,而是专注于渲染。 可以在更广泛的系统中探索关于实现其他功能的许多不同观点和方向。 虽然有很多糟糕的解决方案,但也有好的解决方案,为下一代从精英那里学习最好的想法铺平了道路。

这样更容易被开发者接受。 采用完整的框架来接管你的整个网页意味着你需要重新绘制大部分应用程序,这对于现有的服务器端来说是不可能的。 使用 React 和 Vue 等框架,您可以将其中的一小部分放入现有应用程序中,并且一次仅迁移一个小部件或组件,从而允许开发人员逐步迁移其现有代码。

这两种激励导致第二代框架的快速发展,超越了第一代框架。 从长远来看,这一切实际上都是有道理的,是一个合乎逻辑的演变。 但对于当时身处其中的我来说,这是一次相当令人失望的经历。

首先,工作中关于框架选择的争论不是我们应该使用哪个框架来开发,或者我们是否应该重新绘制我们的应用程序。 相反,它通常是“更快!” 或“它更小了!” 或“这就是您需要的一切!”。 关于函数式编程与面向对象编程也存在争论,许多人指出 FP 是我们所有问题的解决方案。 平心而论编写可维护的 javascript,这样的事情是真的。 仅视口框架最初更小、更快,并且满足您所需的一切(如果您自己完成或缝合很多东西)。 实际上,函数式编程模式解决了很多令 JavaScript 困惑的问题,但我认为总体来说 JS 因它们而更好。

但现实是没有灵丹妙药。 应用一直以来都庞大、臃肿、复杂,状态一直难以管理,路由、SSR等基础问题一直需要解决。 然而,对于我们许多人来说,人们想要的是放弃试图解决所有此类问题的解决方案,并将问题留给读者。 根据我的经验,这些看法通常被开发团队所接受,从而可以快速发布新产品或功能。 但他们没有足够的时间来充分开发所有额外的功能。

编写可维护的js_编写可维护的 javascript

因此,根据我的经验,开发更多时候是围绕这些视口构建的自制框架,其本身臃肿、复杂且极其不可操作。 我觉得人们在 SPA 方面遇到的很多问题都来自于这个破碎的框架系统,而这个框架系统是在 SPA 使用量飙升的时候出现的。 令我非常失望的是,我遇到了一个不能很好地处理路由或其他小细节的新网站。

但另一方面,现有的全业务第一代框架并不能很好地解决这个问题。 部分原因是科技债务负担仍然巨大。 第一代框架是在 ES6 之前构建的,在模块、Babel 和 Webpack 之前构建的,在我们弄清楚很多事情之前构建的。 迭代进化是非常困难的(作为前Ember核心团队成员,我对此深有体会),而彻底重绘它们,就像Angular对Angular2所做的那样,扼杀了它们的发展动力。 因此,当谈到 JavaScript 框架时,开发人员陷入了两难境地 - 要么选择过时的一体化解决方案,要么选择免费并 DIY 一半框架并希望得到最好的结果。

就像我说的,当时非常令人失望,但最终还是有很多创新。 随着找出此类框架的最佳实践,整个 JavaScript 系统发展得非常快,还发生了一些其他关键变化:

到这个时代结束时,一些问题仍然存在。 虽然我们有了比以前更好的模型,但到目前为止,状态管理和反应性一直是棘手的问题。 性能情况也在改善,但仍然存在许多臃肿的SPA。 对于许多开发团队来说,可访问性情况也常常是事后才想到的。 但这一变化为下一代框架铺平了道路。 我想说,我们刚刚进入了下一个框架时代。

全栈框架

就我个人而言,最后一个框架时代确实已经悄然而至。 我认为这是因为我花了 4 年左右的时间深入研究 Ember 渲染层的内部,试图清理前面提到的困扰它作为第一代框架的技术欠款。 但也是因为它更加微妙,因为所有那些第三代框架都是围绕上一代的视口框架构建的。 著名的框架包括:

这个框架随着视口的成熟和巩固而出现。 现在我们都同意组件是构建框架的核心基础,是时候开始标准化应用程序的其他部分——路由器、构建系统、文件夹结构等等。 逐渐地,这个元框架开始构建与第一代一体式解决方案可以提供的相同功能,从组件中选择最佳模式并在它们成熟时将它们合并,然后进一步开发。

到目前为止,SPA 的重点仍然是客户端。 SSR是每个框架都希望解决的问题,但它只是作为一种优化、一种渲染方式,最终会在JS加载完成后被取代。 第一代框架中只有一个敢于做大,那就是 Meteor.js,但其“同构 JS”理念从未真正实现。

但随着应用程序的规模和复杂性降低,这种看法被重新考虑。 我们注意到,组合前端和后端非常有用,因此您可以隐藏单个请求的 API 机密、更改页面返回的标头以及代理 API 请求。 随着 Node 和 Deno 实现越来越多的 Web 标准,服务器端 JS 和客户端 JS 之间的差异每年都在缩小,这显然不再是一个疯狂的想法。 将其与边缘估计和令人惊讶的工具相结合,您将拥有令人难以置信的潜力。

最新一代的框架充分利用了这一潜力,将客户端和服务器无缝地合并在一起,这是多么令人惊奇,我无法用语言来形容。 在过去的 9 个月里,我与 SvelteKit 合作,我坐下来说“我们应该始终这样做”的次数多得我数不清。

以下是我最近完成的一些任务,使用此设置似乎非常简单:

这只是冰山一角。 这些模式有很多非常酷的事情,其中​​最重要的事情之一是它如何重振增量改进的想法,结合服务器和客户端功能,如果用户禁用,客户端可以回退到基本 HTML JavaScript + HTTP。 当我开始在 SPA 工作时,我完全放弃了这些做法,并认为它们只是未来,但我们可能会看到它回来,这真的很酷。

根据经验,根据这个新功能,我将这个框架归类为新一代框架。 曾经未解决或无法解决的问题现在变得微不足道编写可维护的 javascript,只需稍微更改响应处理逻辑即可。 无需任何额外配置即可获得可靠的性能和用户体验。 我们可以根据需要添加一些额外的端点或中间件,而不是构建全新的服务。 这早已改变了人们的生活。

我觉得这一代框架也解决了第一代和第二代框架与其用户之间的一些主要紧张点。 它源于向零配置术语的转变,但我觉得它最终是由已经成熟和稳定的第二代框架的衍生系统驱动的。 第三代框架现在又试图成为一种一体化的解决方案,试图解决我们作为后端开发人员需要解决的所有基本问题,而不仅仅是渲染问题。

现在,社区比以往任何时候都更团结一致地解决困扰 SPA 的所有问题,但重要的是他们共同解决这些问题。

接下来我们应该做什么?

总的来说,我觉得 JavaScript 社区正在朝着正确的方向发展。

今天的开发人员专注于从头开始构建完整应用程序的成熟解决方案,这些解决方案不限于“一个视口”。 与此同时,我们终于开始与原生应用的 SDK 在同一起跑线上竞争,提供开箱即用的完整工具包。

加油,我们还有很多工作要做。 无障碍是 SPA 领域长期存在的问题; 在 GraphQL 之外,我一直认为数据可以用于某些用途(无论喜欢与否,大多数 Web 一直都在 REST 上运行)。 但趋势是对的,如果我们继续朝着共享解决方案迈进,我认为我们可以用比以前更好的方式解决此类问题。

我也对这种模型在网络平台本身之后更进一步的潜力感到兴奋。 Web Components 仍在悄然迭代 SSR 等内容并摆脱全局注册表,这将使它们与第三代框架越来越兼容。 另一方面,WebAssembly 可以以令人难以置信的方式迭代这些模式。 想象一下能够用任何语言编写全栈框架。 同一种 Rust、Python、Swift、Java 等语言最终可以将后端和前端之间的障碍降低到几乎为零,只需在你的系统边缘添加一点 HTML 模板(笑话,虽然有更好的 UX,但这几乎让我们绕了一圈)。

如果我们能够默认为开发人员提供正确的工具,那么网站实际上会看起来更好,用户体验也会看起来更流畅。 其实框架的优缺点并不能解决网站的所有问题,但它会为网站向好的方向发展奠定基础,同时也能让每个开发者有更多的时间专注于其他事情。

结尾

— 推荐阅读 —
☞被挖 40 多人、M1 芯片机密遭窃,苹果急了:还资料,赔钱!
☞乐视回应能活到今天:何止是奇迹,简直“不科学”
☞超越Safari,Edge成为全球第二大受欢迎的桌面浏览器