Flux模式简析

栏目: 后端 · 发布时间: 6年前

内容简介:相比MVC模式,Flux多出了更多的箭头跟图标,但是有个关键性的差别是:所有的剪头都指向一个方向,在整个系统中形成一个闭环。"shut up and show me the code"Dispatcher文件初始化
  • flux 的核心思想是中心化控制,它让所有的请求与改变都只能通过 action 发出,统一 由 dispatcher 来分配。好处是 View 可以保持高度简洁,它不需要关心太多的逻辑,只需要关心传入的数据。中心化还控制了所有数据,发生问题时可以方便查询。
  • flux 缺点也很明显,层级太多,需要重复写太多的冗余代码。
  • Flux_GitHub地址

一个 Flux 应用包含四个部分:

  • Dispatcher,处理动作分发,维持 Store 之间的依赖关系
  • Store,负责存储数据和处理数据相关逻辑
  • Action,触发 Dispatcher
  • View,视图,负责显示用户界面
Flux模式简析
  • 通过上图可以看出来,Flux 的特点就是单向数据流:
    1. 用户在 View 层发起一个 Action 对象给 Dispatcher
    2. Dispatcher 接收到 Action 并要求 Store 做相应的更改
    3. Store 做出相对应更新,然后发出一个 change 事件
    4. View 接收到 change 事件后,更新页面

简单图示对比MVC

  • 基本的MVC数据流
Flux模式简析
  • 复杂的MVC数据流
Flux模式简析
  • 基本的Flux数据流
Flux模式简析
  • 复杂的Flux数据流
Flux模式简析

相比MVC模式,Flux多出了更多的箭头跟图标,但是有个关键性的差别是:所有的剪头都指向一个方向,在整个系统中形成一个闭环。

模式的演变

  • 与其说Flux是MVC模式的颠覆,不如说是对MVC模式的创新
    1. 传统的MVC模式中,View对Model直接修改的方式非常直截了当,适合小型web应用,然而一但web应用中存在多个Model,多个View,那么Model和View之间的决定关系就可能变得混乱,难以驾驭,并且这种模式阻碍了Model和View的组件化拆分。
    2. 而对比上面两个复杂模式下的对比图,我们发现MVC模式下真正的痛点在于: 缺少了一个和用户交互行为有关的action抽象
  • 从代码层面而言,flux无非就是一个常见的event dispatcher,其目的是要将以往MVC中各个View组件内的controller代码片断提取出来放到更加恰当的地方进行集中化管理,并从开发体验上实现了舒适清爽、容易驾驭的“单向流”模式,并且在这种调度模式下面,事情的变化变得清晰可预测。

Flux源码简析

"shut up and show me the code"

这里主要分析Dispatcher文件代码
复制代码

Dispatcher文件初始化

var invariant = require('invariant');
export type DispatchToken = string;
var _prefix = 'ID_';
class Dispatcher<TPayload> {
  _callbacks: {[key: DispatchToken]: (payload: TPayload) => void};
  _isDispatching: boolean;
  _isHandled: {[key: DispatchToken]: boolean};
  _isPending: {[key: DispatchToken]: boolean};
  _lastID: number;
  _pendingPayload: TPayload;

  constructor() {
    this._callbacks = {};
    this._isDispatching = false;
    this._isHandled = {};
    this._isPending = {};
    this._lastID = 1;
  }
  register(callback: (payload: TPayload) => void): DispatchToken {
    var id = _prefix + this._lastID++;
    this._callbacks[id] = callback;
    return id;
  }
  ...
}
复制代码
  • 代码是截取过的,这里主要是注册一个DispatchToken函数,前缀'ID_'加上自增的++确保唯一(一个store对应多个id应该也是可行的)
    • callbacks,就是DispatchToken和函数回调的一个Dictionary。
    • isDispatching,体现当前Dispatcher是否处于dispatch状态。
    • isHandled,通过token去检测一个函数是否被处理过了。
    • isPending,通过token去检测一个函数是否被提交Dispatcher了。
    • lastID,最近一次被加入Dispatcher的函数体的UniqueID,即DispatchToken。
    • pendingPayload,需要传递给调用函数的参数。

dispatch方法

dispatch(payload: TPayload): void {
    invariant(
      !this._isDispatching,
      'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.'
    );
    this._startDispatching(payload);
    try {
        for(var id in this._callbacks) {
    if (this._isPending[id]) {
        continue;
    }
    this._invokeCallback(id);
}} finally {
    this._stopDispatching();
}}

isDispatching(): boolean {
    return this._isDispatching;
}

_invokeCallback(id: DispatchToken): void {
    this._isPending[id] = true;
    this._callbacks[id](this._pendingPayload);
    this._isHandled[id] = true;
}

_startDispatching(payload: TPayload): void {
for(var id in this._callbacks) {
    this._isPending[id] = false;
    this._isHandled[id] = false;
}
this._pendingPayload = payload;
this._isDispatching = true;
}

_stopDispatching(): void {
    delete this._pendingPayload;
    this._isDispatching = false;
}
复制代码
  • 主要是判断函数是否处于pending状态,将非pending状态的callback通过_invokeCallback执行,所有执行完了以后,通过_stopDispatching恢复状态。
    1. _startDispatching函数的作用,是将所有注册的callback的状态都清空,并标记Dispatcher的状态进入dispatching
    2. _invokeCallback函数很简单,当真正调用callback之前将其状态设置为pending,执行完成之后设置为handled

waitFor方法

waitFor(ids: Array<DispatchToken>): void {
    invariant(
      this._isDispatching,
      'Dispatcher.waitFor(...): Must be invoked while dispatching.'
    );
    for (var ii = 0; ii < ids.length; ii++) {
      var id = ids[ii];
      if (this._isPending[id]) {
        invariant(
          this._isHandled[id],
          'Dispatcher.waitFor(...): Circular dependency detected while ' +
          'waiting for `%s`.',
          id
        );
        continue;
      }
      invariant(
        this._callbacks[id],
        'Dispatcher.waitFor(...): `%s` does not map to a registered callback.',
        id
      );
      this._invokeCallback(id);
    }
  }
复制代码
  • 简单的认为,dispatch方法对回调的遍历是简单、同步式的。当在执行callback过程中遇到waifFor方法时,对当前callback的调用就会中断,wairFor方法会根据声明的依赖重新确定遍历顺序,当所有依赖都被执行后,原先中止的callback才会继续执行。
  • ps:下面这段话来自于复制(权当参考)
    1. 首先是一个Invariant判断当前必须处于Dispatching状态。一开始比较难理解,简单来说就是,如果不处于Dispatching状态中,那么说明压根没有函数在执行,那你等谁呢?
    2. 然后该函数从DispatchToken的数组中进行遍历,如果遍历到的DispatchToken处于pending状态,就暂时跳过他。
    3. 但是,在这有个必要的循环以来的检查,试想如下情况,如果A函数以来B的Token, B函数依赖A的Token,就会造成“死锁”。所以,当一个函数依赖的对象处于pending,说明这个函数已经被开始执行了,但是如果同时该函数没有进入handled状态,说明该函数也被卡死了。
    4. 检查token对应的callback是否存在,调用这个token对应的函数。
  • ps: 这里面的部分图片以及说明来自于第三方,但是想不起来了:joy:

以上所述就是小编给大家介绍的《Flux模式简析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

反应式设计模式

反应式设计模式

Roland Kuhn、Brian Hanafee、Jamie Allen / 何品、邱嘉和、王石冲、林炜翔审校 / 清华大学出版社 / 2019-1-1 / 98.00 元

《反应式设计模式》介绍反应式应用程序设计的原则、模式和经典实践,讲述如何用断路器模式将运行缓慢的组件与其他组件隔开、如何用事务序列(Saga)模式实现多阶段事务以及如何通过分片模式来划分数据集,分析如何保持源代码的可读性以及系统的可测试性(即使在存在许多潜在交互和失败点的情况下)。 主要内容 ? “反应式宣言”指南 ? 流量控制、有界一致性、容错等模式 ? 得之不易的关于“什么行不通”的经验 ? ......一起来看看 《反应式设计模式》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具