浅析前端框架模式的发展

1,296 阅读8分钟

我的框架学习笔记0.0

web1.0 -> ajax 前后端逐步分离

在开始的开始,前端概念还未出现,开发一个应用可能只需要5、6个人的小团队。那时的系统构架可能是这个样子:

在业务量少的情况下,这样的框架不存在什么问题。比如平时做的一些小项目

但是随着业务量的增加,server的体系会逐步庞大,有时甚至需要建设一个服务器进行存储,随之而来的是调试困难:在本地无法进行client端的调试。

另外业务的增加也会增加client端JSP代码的维护难度,特别是client端的业务逻辑混杂在JSP内。

这样的架构像是没有分工的富士康生产线,一个工人要负责一部手机的整机组装,虽然在订单少时可能不会影响生产效率(1个人每天生产一台手机,10个人生产10台手机),但是面对大量的订单,将工序拆分,同样的一个人只参与其中一道工序,虽然需要更多的工人数量,但是手机的生产效率指数级的提升(1个人每天可以完成1000次同一道工序,组装手机需要100道工序的话,100个人每天可以生产1000部手机)

所以,我们将现在的分工进行拆分:

这样的框架被称为后端的MVC时代,此时前后端开始逐步分离。前端只需要在本地编写好相应的页面,然后交给后端,让他们可以根据模板进行嵌套。但是此时的前端依旧职能不清,前端对于后端的依赖程度较大。

直到出现了——AJAX

有了AJAX,前端可以通过AJAX与后端进行数据交互,那么架构图会变成这样:

此时的前端只需要开发页面的部分内容,数据则通过AJAX由后端取得。另外,AJAX使得页面实现部分刷新,极大的减少了之前需要反复开发的页面。此时只要借助jQuery等用于操作DOM的库,基本就可以完全cover前端的工作。

但是,移动端发展的速度太快了,需要在客户端处理的逻辑越来越复杂,不单单局限于交互体验,甚至需要处理很多业务逻辑。例如有些购物车的设计,无需向服务器端发送请求即可向购物车中添加商品并立刻计算出总价格。Web端的功能越来越强,需要组织的代码也越来越多。因此,前端也逐渐引入了后端的架构思想——MVC。

MVC模式

在2010年前后,“单页面应用”的概念逐渐被重视,而诸如“BackBone”Knockout等框架也逐渐受到关注。

此时的前端框架借鉴了已在后端成熟的MVC设计模式,对于前端的代码进行精细化分工。在MVC模式中,M即为数据模型(Model),V视图(View),而C则为控制器(Controller)。

在理论上,MVC间的关系是单向通信

  1. View 传送指令到 Controller
  2. Controller 完成业务逻辑后,要求 Model 改变状态
  3. Model 将新的数据发送到 View,用户得到反馈

但在实际操作中,MVC会因为用户的指令而有如下的变形:

一种是通过View接受用户的指令,并将指令传递给Controller。
另一种则是controller直接接受用户指令。

BackBone的实践中,MVC模式演化为:

  1. 用户可以向View发送指令(DOM 事件),再由View直接要求Model 改变状态

  2. 用户也可以直接向Controller发送指令(改变URL触发hashChange 事件),再由 Controller 发送给 View

改变URL触发hashChange 事件的设计思路与 表驱动编程 类似。

  1. Controller 非常薄,只起到路由的作用,而View 非常厚,业务逻辑都部署在View。所以,Backbone索性取消了 Controller,只保留一个Router(路由器)

表驱动编程

表驱动法是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越发杂,查表法也就愈发能够提高效率。

eventBus

也是借鉴自JAVA的吧 可以实现MVC间的信息沟通,属于JS异步操作中的事件监听模式,可通过jQuery内置的on,off 以及 trigger 方法实现(在VUE中有专门的API)。

前端的MV*

在前端的发展中,由MVC模式衍生了很多其它MV*模式,而其中最为常用的是MVVM。另外,尽管在前端框架中使用较少,但在安卓等native开发时,MVP模式也同样重要。

MVP

MVP 模式将 Controller 改名为 Presenter,P指的是Presenter,presenter可以理解为一个中间人,它负责着View和Model之间的数据流动,防止View和Model之间直接交流。此外MVP的通信方向也变为了双向的数据流。

  1. 各部分之间的通信,都是双向的。

  2. View 与 Model 不发生联系,都通过 Presenter 传递。

  3. View 非常薄,不部署任何业务逻辑,称为"被动视图"(Passive View),即没有任何主动性,而 Presenter非常厚,所有逻辑都部署在那里。

MVVM

MVVM 是 Model-View-ViewModel 的缩写,ViewModel可以理解为在MVP中presenter基础上的进阶版,此外MVVM基本上与MVP模式完全一致。

MVVM采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。

在MVVM中,View是ViewModel的外在显示,与ViewModel的数据同步。MVVM模式的优点在于是View和Model之间被分离开来。view不知道model的存在,viewmodel和model也觉察不到view。事实上,model也完全忽略viewmodel和view的存在。是一种非常松散耦合的设计。

Flux 以及 Redux

不可否认,MVC模式依旧是最经典的设计模式,但MVC模式在前端的缺陷也显而易见:数据流混乱,难以管理。 对此,Facebook在这个基础上对MVC做出了改变,那就是——单向数据流(Unidirectional User Interface Architecture)。

Facebook在Flux Overview中举的例子,当我们希望在一个界面上同时展示未读信息列表与未读信息的总数目的时候,对于MV*就有点恶心了,特别是当这两个组件不在同一个ViewModel/Controller中的时候。一旦我们将某个未读信息标识为已读,会引起控制已读信息、未读信息、未读信息总数目等等一系列模型的更新。特别是很多时候为了方便我们可能在每个ViewModel/Controller都会设置一个数据副本,这会导致依赖连锁更新,最终导致不可预测的结果与性能损耗。而在Flux中这种依赖是反转的,Store接收到更新的Action请求之后对数据进行统一的更新并且通知各个View,而不是依赖于各个独立的ViewModel/Controller所谓的一致性更新。从职责划分的角度来看,除了Store之外的任何模块其实都不知道应该如何处理数据,这就保证了合理的职责分割。这种模式下,当我们创建新项目时,项目复杂度的增长瓶颈也就会更高,不同于传统的View与ViewLogic之间的绑定,控制流被独立处理,当我们添加新的特性,新的数据,新的界面,新的逻辑处理模块时,并不会导致原有模块的复杂度增加,从而使得整个逻辑更加清晰可控。

Flux形成了一条 Action -> Dispatcher -> Store ->View 的单向数据流。在这里Dispatcher会严格限行我们操作数据的行为,而Store也不会暴露setter接口,让其随意被修改。最终,这样的一套框架在大多数场景下,比MVC更加完美。

Redux是Flux的所有变种中最为出色的一个,并且也是当前Web领域主流的状态管理工具,其独创的理念与功能深刻影响了GUI应用程序架构中的状态管理的思想。Redux将Flux中单例的Dispatcher替换为了单例的Store,即也是其最大的特性,集中式的状态管理。并且Store的定义也不是从零开始单独定义,而是基于多个Reducer的组合,可以把Reducer看做Store Factory。

参考资料