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模式简析》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Out of Control

Out of Control

Kevin Kelly / Basic Books / 1995-4-14 / USD 22.95

Out of Control is a summary of what we know about self-sustaining systems, both living ones such as a tropical wetland, or an artificial one, such as a computer simulation of our planet. The last chap......一起来看看 《Out of Control》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具