Flux模式簡析

  • flux 的核心思想是中心化控制,它讓全部的請求與改變都只能經過 action 發出,統一 由 dispatcher 來分配。好處是 View 能夠保持高度簡潔,它不須要關心太多的邏輯,只須要關心傳入的數據。中心化還控制了全部數據,發生問題時能夠方便查詢。
  • flux 缺點也很明顯,層級太多,須要重複寫太多的冗餘代碼。
  • Flux_GitHub地址

一個 Flux 應用包含四個部分:

  • Dispatcher,處理動做分發,維持 Store 之間的依賴關係
  • Store,負責存儲數據和處理數據相關邏輯
  • Action,觸發 Dispatcher
  • View,視圖,負責顯示用戶界面

流程圖

  • 經過上圖能夠看出來,Flux 的特色就是單向數據流:
    1. 用戶在 View 層發起一個 Action 對象給 Dispatcher
    2. Dispatcher 接收到 Action 並要求 Store 作相應的更改
    3. Store 作出相對應更新,而後發出一個 change 事件
    4. View 接收到 change 事件後,更新頁面

簡單圖示對比MVC

  • 基本的MVC數據流

  • 複雜的MVC數據流

  • 基本的Flux數據流

  • 複雜的Flux數據流

相比MVC模式,Flux多出了更多的箭頭跟圖標,可是有個關鍵性的差異是:全部的剪頭都指向一個方向,在整個系統中造成一個閉環。git


模式的演變

  • 與其說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"github

這裏主要分析Dispatcher文件代碼
複製代碼

Dispatcher文件初始化web

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: 這裏面的部分圖片以及說明來自於第三方,可是想不起來了😂
相關文章
相關標籤/搜索