39

前端技术栈(一):从MV*到Flux

 5 years ago
source link: https://blog.csdn.net/TurkeyCock/article/details/88373485?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近要开始搞网页端钱包,本着干一行爱一行的原则,撸起了前端框架。

项目基于蚂蚁金服的dva框架,实际上是对几个流行的开源框架的整合,技术栈包括:

  • react
  • react-router
  • redux
  • redux-saga
  • dva
  • antd

在开始介绍之前,先说一说MV*。大家一定都听说过MVC,在这之后又衍生出了MVP和MVVM,这些都可以统称为MV*。但是,随着前端代码复杂度的增加,人们发现越来越难以管理程序的状态,模块之间耦合严重,代码难以调试,因此很多人认为“前端MVC已死”。

UJrMviz.png!web 2014年,facebook提出了一个新的概念:Flux,旨在解决这些问题,其核心思想是“ 组件化 + 单向数据流 ”。这个框架很快流行了起来,并且逐渐成为目前的主流前端框架之一。为了更深刻地理解这一变化,我们来逐一比较一下它们之间的异同:

BrUj6rE.png!web 用户首先通过View发起交互,View调用Controller执行业务逻辑,Controller修改Model,然后View通过观察者模式检测到Model的变化(具体表现形式可以是Pub/Sub或者是触发Events),刷新界面显示。

从这里可以看出,主要业务逻辑都在Controller中,Controller会变得很重。MVC比较明显的缺点:

  • View依赖特定的Model,无法组件化
  • View和Controller紧耦合,如果脱离Controller,View难以独立应用(功能太少)

EV3yeuA.png!web 为了克服MVC的上述缺点,MVP应运而生。在MVP中,View和Model是没有直接联系的,所有操作都必须通过Presenter进行中转。View向Presenter发起调用请求,Presenter修改Model,Model修改完成后通知Presenter,Presenter再调用View的相关接口刷新界面。这样,View就不需要监听具体Model的变化了,只需要提供接口给Presenter调用就可以了。MVP具有以下优点:

  • View可以组件化,不需要了解业务逻辑,只需提供接口给Presenter
  • 便于测试:只需要给Presenter mock一个View,实现View的接口即可

mA736br.png!web 为了进一步解放生产力,把Presenter中调用View的接口同步数据变化的重复工作抽象出来,做成一个binder模块,这就变成了MVVM。开发者只需要指明绑定关系,binder模块会自动完成数据同步,这就是所谓的“ 双向数据流 ”,不管哪一端的数据发生变化,都会立即同步到另一端。实际上,Vue.js、Angular这些流行的前端框架都使用了双向数据流设计。

双向数据流极大地简化了开发者的工作,但是诟病也随之而来。由于绑定的随意性,某个View对Model进行的修改有可能会对其他的View造成“连锁反应”,再加上各种异步回调,给代码调试造成了很大的困难,往往难以定位数据到底是被谁修改掉的。用专业一点的术语来讲,代码的“ 可预测性 ”非常差。因此,为了提高可预测性,很多人主张回归到“单向数据流”模式,其中的典型代表就是facebook的Flux框架。

其实Flux并不是什么新鲜事物,其背后还是经典的MVC思想,但是实现方式上有所不同。Flux的核心是“组件化+单向数据流“,下面逐一进行介绍。

4.1组件化

在传统的MVC设计中,Model中不仅要存储应用程序数据,还需要存储UI状态。另一方面,Controller中不仅要处理业务逻辑,还需要实现各种事件处理逻辑。如果把这部分内容抽出来,和View组合在一起,就变成了“ 组件 ”。这样一来,各个模块都可以各司其职,专注于自己的领域,代码的可读性和复用性都可以得到提高。

2Q7BJrM.png!web 在实际编程中,一般把纯界面展示的View实现成一个“ 无状态组件 ”,在其上层再包装一个Controller-View(也可以称为Container),专门监听事件并更新数据,然后把数据作为props传递给View。这种编程模式可以最大程度地提高组件的可复用性。

4.2单向数据流

为了提高代码的可预测性,Flux采用单向数据流设计。这里引入了3个新概念:

  • Store:每个程序可以拥有多个Store,存储应用程序状态的不同部分。Store对View是只读的,只有Dispatcher可以通过Store注册的回调函数修改Store的内容
  • Action:当发生交互,需要修改Store内容时,需要发起一个Action,包含对应的type和payload
  • Dispatcher:当接收到Action时,会通过回调函数调用所有Store的,完成数据修改

当Store数据发生变化时,会发送一个事件,View或者Controller-View可以监听这个事件,然后完成界面刷新。整个过程是“单向”的,如果View想要继续修改Store,必须重新发起一个Action。

当然,除了View以外,服务器或者Web API也可以直接发送Action给Dispatcher,这就是为什么图中Dispatcher有两个输入的原因。

NjYfQnb.png!web

更为详细的Flux流程参见下图:

RRbqqaB.png!web

通过以上分析可以发现,所谓单向数据流并不是什么新鲜概念,实际上最最经典的MVC设计中,数据流就是单向的。虽然Flux官方宣称它们不是MVC,但我个人认为其实它实际想说的是MVVM,因为MVVM才是双向数据流。

当然,Flux也不是完美的,在多Store协同管理上存在一定的设计缺陷,这也是后来Redux出现的原因,且听下回分解。

最后,以一张思维导图结束本篇文章:

rmIVfiu.png!web

更多文章欢迎关注“鑫鑫点灯”专栏: https://blog.csdn.net/turkeycock

或关注飞久微信公众号: F32iaaY.jpg!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK