在这些流行的前端框架(AngularJS、Backbone 和 Ember)出现之前,我们在服务器端渲染模板,然后将生成的 HTML 页面发送到浏览器端。当时流行的框架包括:
Django(Python)——最初发布于 2005 年 7 月 21 日,大约 13 年前;
Ruby on Rails——最初发布于 2005 年 12 月 13 日,大约 13 年前;
Symphony(PHP)——最初发布于 2005 年 10 月 22 日,大约 13 年前。
这些框架以 MVC(Model-View-Controller)开发结构的概念为基础。Model 代表数据的“形状”,View 是用于“显示”数据的模板,Controller 用于“连接”二者。
当时肯定已经有 JavaScript 了,但我们说得更多的是 jQuery 滑块和一些可以用来制作弹跳效果的库……
基于这些框架构建的应用程序有一些问题,但总体来说一切都还好。然后有一天,Ryan Dahl 有了一个很棒的想法,他认为 JavaScript 不应该只是用来做一些愚蠢的动画,于是他开发了 Node.js 的第一个版本,让开发人员可以在服务器端编写 JavaScript。
Express.js(后端)——最初发布于 2010 年 11 月 16 日,大约 8 年前。
Backbone.js(前端)——最初发布于 2010 年 10 月 12 日,大约 8 年前。
AngularJS(前端)——最初发布于 2010 年 10 月 20 日,大约 8 年前。
Ember.js(前端)——最初发布于 2011 年 12 月 8 日,大约 7 年前。
应用程序的开发方式开始出现重大的转变。之前完全由服务器端处理 MVC 框架开始出现分裂——一个是处理 MC(Model 和 Controller)的服务器端,一个是使用上述 JavaScript 框架处理 View 的前端客户端。在一些早期框架中,它们还在 View 中包含了 Model 和 Controller,也就是双重 Model 和 Controller,一些在前端,一些在后端——现在看起来好像涉及了很多代码。
Facebook 发展迅猛,并成为全球最大的 Web 应用程序,接踵而来的是一系列巨大的挑战。最令人头疼的一个问题是,如何在在标题栏中显示通知的数量。
用户希望在 Facebook 应用程序上看到通知数量实时更新,但这些通知数量通常不准确。问题在于,Web 应用程序很难知道应用程序的某个部分发生了变化(例如,当你阅读时消息),然后再另一个位置显示变化的内容(例如,将未读通知数量减少一)。
这个可以通过重新加载页面来解决——但 Facebook 的 1000 名热情洋溢的员工认为是时候采取行动做一些不一样的事情了。于是,他们重新思考前端框架应该如何处理信息,并创建了 React。
这个新框架擅长于渲染 HTML,但并没有提供太多有关“如何”开发应用程序的方式。他们还推出了 Flux,最终发展成为 Redux(Redo-Flux)。以下是 2014/2015 期间放在 Flux 网站上的视频,对 Flux 和 React 进行了介绍。
Redux 将应用程序所有的动态信息都保存在一个 JavaScript 对象中。当应用程序的某个部分需要显示某些信息时,它将从服务器请求数据,更新这个 JavaScript 对象,然后向用户显示这些数据。通过将所有信息保存在一个地方,无论在什么位置,应用程序都能显示正确的信息,这解决了 Facebook 的通知更新问题。
于是一个新框架出现了,即 React Redux。照理说,Facebook 解决了他们的问题,从此以后就风平浪静了,不是吗?
问题在于,人们(包括我自己)开始使用单个 JavaScript 对象来保存所有的信息,包括服务器端提供的每一条数据。这样可以让所有信息保持最新,但也存在三个不足:
它需要大量额外的代码,你需要花费更多的时间。
存在“陈旧数据”,也就是说应用程序之前的状态数据可能是不需要的,你不希望这些数据继续存在。
对于新的开发人员来说,它的学习曲线经历冲破了天花板,导致他们很难掌握前端 Web 开发。
我们设法将一个相对简单的任务(向用户显示数据)从 MVC 框架转为单体前端应用,前端代码比后端多 10 倍。我最近开发了一个简单的应用程序,并使用 WakaTime 来测量我在编码上所花费的时间。结果如下:
React Redux 前端库——32 小时
Express + Mongoose 后端库——4 小时
我在前端花了比后端多 8 倍的时间。让我们深入了解一下为什么它需要这么多额外的代码。以下是基本的数据请求调用(例如获取所有用户)需要遵循的步骤:
创建组件以显示用户列表
创建对 API 的 fetch 调用
在状态中添加新字段
添加一个更新状态的操作
添加一个转换方法,用于执行 fetch 调用,并使用新操作更新状态
使用 connect() 将转换函数添加到组件中
使用 connect() 从 Redux 状态中提取数据
在组件的 prop 类型中声明转换函数和提取的数据字段
在 componentDidMount() 函数中调用转换方法
在 DOM 中渲染数据
总共需要 10 个步骤。在 Ruby on Rails 时代,我只需要将数据提供给 HTML 模板就可以获得相同的结果。我感觉有些东西需要做出改变。
Redux 非常适合用来保持前端应用程序的同步,但它也带来了其他问题(如前所述)。
从本质上说,我们重写了整个前端,只为了解决一些琐碎的问题……
Facebook 也意识到这一点,并开始推出 GraphQL 来解决这个些问题。GraphQL 目前是一个热语,但我不确定是否有人真正理解为什么它会这么酷。
GraphQL 与 Redux 完全不同。Facebook 再一次为我们提供了一个惊人的产品,但仍然没有说明白为什么这个产品如此重要。
简单地说,GraphQL 是一辆汽车,而 Redux 是一匹马。
我之所以将这两者比喻为马和汽车,是因为马和汽车几乎没有什么相似点——一个是四条腿的动物,一个是带轮子的机器。然而,它们都试图达成相同的目标,即让一个人去到他们需要去的地方。汽车在街道上行驶并使用燃料,而马是一种可以跳过岩石的动物。两者都有不同的优势和用例,但一般来说,汽车会比马更快地到达最终目的地。
官方文档将 GraphQL 描述为“一种 API 查询语言”,这样的描述模棱两可。基本上,它们所谓的查询语言是指用数百个 HTTP 端点替换 API。但这项技术还很年轻,文档和相关支持技术仍然有点难以理解,所以学习曲线比较陡峭,请看下面的例子。
GraphQL 将以下的端点:
GET /users/1234567890
POST /cars
PUT /example/endpoints
替换成自定义查询:
{
user(id: "1234567890") {
name,
email
}
}
然后返回:
{
"user": {
"name": "Luke Skywalker",
"email": "luke@iamyourfather.com"
}
}
因为只请求需要的数据,就不需要发出很多服务器请求,这意味着你不需要使用很多代码来处理这些服务器请求。因此,你可以避免编写大量不必要的代码,从而节省大量的时间。
简单地说,GraphQL不会取代 Redux。但不管怎样,它鼓励你不要将所有信息保存在单个对象中。因为每个查询都只为应用程序的一部分获取数据——而不是全部。在应用程序范围的数据源中保存特定于应用程序某个部分的信息是一种反模式(并且根本不合逻辑)。
使用 GraphQL 可以移除对 Redux 的依赖,从而删除大量不必要的代码。
还需要注意的是,Redux 和 GraphQL 可以在应用程序中共存。如果你已经使用了 Redux,可以将 GraphQL 逐步集成到 Redux 应用程序中。这里是一些关于如何将两者结合起来使用的文档(https://s3.amazonaws.com/apollo-docs-1.x/redux.html)。
于是,Redux 成为了一个可选项。你可以用它来解决一些琐碎的问题,但同时也带来了额外的开销,当然,你也可以考虑使用其他东西来完成这些任务。
Redux 是当时解决页面局部刷新问题的一个好方法。然而,自从它出现以来,Web 开发行业已经经历了指数级的增长,然后 Web Socket 出现了。
Web Socket 是服务器端和客户端之间的开放连接,服务器端可以通过 Web Socket 告诉客户端何时做出更新。GraphQL 通过订阅的方式直接支持 Web Socket,于是我们就可以使用这些订阅来更新我们希望保持同步的应用程序的某些部分。
主要的区别在于,我们不是让客户告诉我们需要更新哪些东西(使用 Redux 时是这样的),而是让服务器端告诉客户端必须更新数据。我们得到的效果是一样的。以下是一些如何使用 Mongodb 或 Mongoose 直接实现 Web Socket 或订阅的示例:
http://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-change-streams.html
https://mongoosejs.com/docs/api.html#model_Model.watch
GraphQL 已经推出一段时间了,现在处于可以被用在生产环境中的阶段。不过,它的文档仍然不是很好理解,而且需要事先了解 JavaScript 和服务器端的相关知识。官方网站提供了一个非常好的教程(https://graphql.org/learn/)。
还有一些很有用的库可以帮助你逐步将其集成到现有产品中。不用担心,你不需要一步到位,随着时间的推移,这些库将帮你逐步转换你的应用程序。
https://hackernoon.com/goodbye-redux-26e6a27b3a0b
前端新趋势,可以关注 QCon 全球软件开发大会,从实践中积累的前端架构经验,典型的前端框架应用经验,新型框架与设计思路三个方面探索前端研发之路。大会9 折报名中,立减 680 元。有任何问题欢迎咨询票务经理 Ring,电话:010-84782011,微信:qcon-0410。