Flutter Redux 中間件執(zhí)行順序

Redux 通過中間件的機制,可以解耦業(yè)務(wù)邏輯韵吨,更加靈活的處理異步的操作入挣。

在實際使用的過程中,每個 中間件的 call 函數(shù)中鲫售,大多數(shù)情況需要調(diào)用 next(action)共螺, 否則中間件的鏈條斷了,后面的中間件和Reducer就不執(zhí)行了情竹。

那么 next(action) 什么時候調(diào)用呢藐不? 這個問題困擾了我很久, 于是我做了下面的實驗秦效。

首先雏蛮,我定義了3個 Action:

  enum Actions { action1, action2, action3 }

分別處理Action 的 Reducer:

  int reducer(int state, dynamic action) {
    if (action == Actions.action1) {
      print('Reducer action1');
    } else if (action == Actions.action2) {
      print('Reducer action2');
    } else if (action == Actions.action3) {
      print('Reducer action3');
    }
    return state;
  }

下面是重點: 中間件。

中間件的執(zhí)行過程

void middleware1(Store<int> store, dynamic action, NextDispatcher next) {
  print('Middleware 1  A');
  next(action);
  print('Middleware 1  B');
}

void middleware2(Store<int> store, dynamic action, NextDispatcher next) {
  print('Middleware 2  A');
  next(action);
  print('Middleware 2  B');
}

void middleware3(Store<int> store, dynamic action, NextDispatcher next) {
  print('Middleware 3  A');
  next(action);
  print('Middleware 3  B');
}

執(zhí)行上面的代碼棉安, 當發(fā)出 dispatch Action1 時底扳, 執(zhí)行的結(jié)果是:

flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Middleware 3  A
flutter: Reducer action1
flutter: Middleware 3  B
flutter: Middleware 2  B
flutter: Middleware 1  B

結(jié)論:
Redux 當發(fā)出 Action 時铸抑, 會調(diào)用第一個中間件的 call 方法贡耽, 然后由中間件依次調(diào)用 next(action) 來執(zhí)行所有加入到 middleware 數(shù)組里面的中間件,最后一個中間件會調(diào)用 reducer鹊汛。

如果想要攔截某個 Action蒲赂, 就在中間件的 call 方法中不調(diào)用 next(action) , 這樣 reducer 就不會執(zhí)行了刁憋。

中間件中發(fā)出其他 Action

經(jīng)常出現(xiàn)的場景滥嘴,在中間件中,發(fā)出其他的Action 進行狀態(tài)控制至耻, 比如在網(wǎng)絡(luò)請求中間件中若皱, 收到數(shù)據(jù)后發(fā)送 Action 更改狀態(tài)镊叁。

修改上面 中間件部分 middleware2 的代碼, 在 調(diào)用 next(action) 前面 dispatch 發(fā)出Action2。

void middleware2(Store<int> store, dynamic action, NextDispatcher next) {
  print('Middleware 2  A');

  if (action == Actions.action1) {
    print('Dispatch action2');
    store.dispatch(Actions.action2);
    print('Dispatch action2 end');
  }

  next(action);
  print('Middleware 2  B');
}

執(zhí)行上面的代碼走触, 當發(fā)出 dispatch Action1 時晦譬, 執(zhí)行的結(jié)果是:

flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Dispatch action2
flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Middleware 3  A
flutter: Reducer action2
flutter: Middleware 3  B
flutter: Middleware 2  B
flutter: Middleware 1  B
flutter: Dispatch action2 end
flutter: Middleware 3  A
flutter: Reducer action1
flutter: Middleware 3  B
flutter: Middleware 2  B
flutter: Middleware 1  B

結(jié)論:
在中間件中,調(diào)用 dispatch 發(fā)送其他Action互广, 會遞歸先處理新發(fā)出的 Action敛腌, 所以這時候 next(action) 寫在哪里就很重要了。

如果 reducer 執(zhí)行時惫皱,需要依賴新發(fā)出的 Action 對狀態(tài)的改變像樊, 那就要在 next(action) 前面 dispatch 發(fā)出新的 Action锻煌。

如果 dispatch 新的 Action 需要依賴于本次處理的 Action 對狀態(tài)的改變刽肠,那就要在 next(action) 后面 dispatch 發(fā)出新的 Action茂契, 這種情況更常見一些撩鹿。

異步邏輯會改變中間件的執(zhí)行順序

在 Dart 語言中唇撬, 可以使用 async/await 將異步的代碼優(yōu)雅的用同步的方式來表示埠胖。所以使用 await 調(diào)用的方法會改變代碼的執(zhí)行順序析既。

在 Redux 中笆焰, 中間件是處理異步操作的好地方韩脑, 在中間件中使用 await 調(diào)用 async 的方法氢妈, 也會改變中間件的執(zhí)行順序。

為了方便實驗段多,我在代碼中加入了一個空的 async 方法:

Future<Null> doNothing() async {}

修改 middleware2 的代碼首量, await 調(diào)用 doNothing 方法。

Future<Null> middleware2(Store<int> store, dynamic action, NextDispatcher next) async {
  print('Middleware 2  A');

  if (action == Actions.action1) {
    await doNothing();
    print('Dispatch action2');
    store.dispatch(Actions.action2);
    print('Dispatch action2 end');
  }

  next(action);

  print('Middleware 2  B');
}

執(zhí)行上面的代碼进苍, 當發(fā)出 dispatch Action1 時加缘, 執(zhí)行的結(jié)果是:

flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Middleware 1  B
flutter: Dispatch action2
flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Middleware 3  A
flutter: Reducer action2
flutter: Middleware 3  B
flutter: Middleware 2  B
flutter: Middleware 1  B
flutter: Dispatch action2 end
flutter: Middleware 3  A
flutter: Reducer action1
flutter: Middleware 3  B
flutter: Middleware 2  B

為了更好的說明問題, 再次修改 middleware2 的代碼觉啊, 將 await 調(diào)用 doNothing 方法和 dispatch 新的Action 方法 放到了 next(action) 的后面拣宏。

Future<Null> middleware2(Store<int> store, dynamic action, NextDispatcher next) async {
  print('Middleware 2  A');
  next(action);

  if (action == Actions.action1) {
    await doNothing();
    print('Dispatch action3');
    store.dispatch(Actions.action3);
    print('Dispatch action3 end');
  }

  print('Middleware 2  B');
}

執(zhí)行上面的代碼, 當發(fā)出 dispatch Action1 時杠人, 執(zhí)行的結(jié)果是:

flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Middleware 3  A
flutter: Reducer action1
flutter: Middleware 3  B
flutter: Middleware 1  B
flutter: Dispatch action3
flutter: Middleware 1  A
flutter: Middleware 2  A
flutter: Middleware 3  A
flutter: Reducer action3
flutter: Middleware 3  B
flutter: Middleware 2  B
flutter: Middleware 1  B
flutter: Dispatch action3 end
flutter: Middleware 2  B

結(jié)論:
需要注意勋乾,如果在 調(diào)用 next(action) 之前, 使用 await 調(diào)用嗡善, 會阻塞住整個中間件的鏈式調(diào)用辑莫,然后在 await 位置立刻返回, 造成不符合預(yù)期的結(jié)果罩引。

如果要在中間件中使用異步操作各吨, 需要放在 next(action) 之后, 這樣不會影響其他的中間件調(diào)用袁铐, 用可以把異步的邏輯放到最后執(zhí)行揭蜒。

特別注意

本代碼是在 Flutter 0.5.6 和 Dart 2.0.0-dev.63.0 環(huán)境下的測試結(jié)果横浑, 如果在 Dart 2.0.0-dev.58.0 環(huán)境下, 運行的結(jié)果和上面的結(jié)果是不同的屉更。

這是因為 Dart 語言 改變了 async/await 的執(zhí)行方式伪嫁, 我認為新版本的修改是合理的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偶垮,一起剝皮案震驚了整個濱河市张咳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌似舵,老刑警劉巖脚猾,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砚哗,居然都是意外死亡龙助,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門蛛芥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來提鸟,“玉大人,你說我怎么就攤上這事仅淑〕蒲” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵涯竟,是天一觀的道長赡鲜。 經(jīng)常有香客問我,道長庐船,這世上最難降的妖魔是什么银酬? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮筐钟,結(jié)果婚禮上揩瞪,老公的妹妹穿的比我還像新娘。我一直安慰自己篓冲,他們只是感情好李破,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纹因,像睡著了一般喷屋。 火紅的嫁衣襯著肌膚如雪琳拨。 梳的紋絲不亂的頭發(fā)上瞭恰,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音狱庇,去河邊找鬼惊畏。 笑死恶耽,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的颜启。 我是一名探鬼主播偷俭,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缰盏!你這毒婦竟也來了涌萤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤口猜,失蹤者是張志新(化名)和其女友劉穎负溪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體济炎,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡川抡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了须尚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片崖堤。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耐床,靈堂內(nèi)的尸體忽然破棺而出密幔,到底是詐尸還是另有隱情,我是刑警寧澤撩轰,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布老玛,位于F島的核電站,受9級特大地震影響钧敞,放射性物質(zhì)發(fā)生泄漏蜡豹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一溉苛、第九天 我趴在偏房一處隱蔽的房頂上張望镜廉。 院中可真熱鬧,春花似錦愚战、人聲如沸娇唯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塔插。三九已至,卻和暖如春拓哟,著一層夾襖步出監(jiān)牢的瞬間想许,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留流纹,地道東北人糜烹。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像漱凝,于是被迫代替她去往敵國和親疮蹦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言 最近幾天對 redux 的中間件進行了一番梳理茸炒,又看了 redux-saga 的文檔愕乎,和 redux-thu...
    Srtian閱讀 32,687評論 9 40
  • http://gaearon.github.io/redux/index.html ,文檔在 http://rac...
    jacobbubu閱讀 79,919評論 35 198
  • 前言 本文 有配套視頻壁公,可以酌情觀看妆毕。 文中內(nèi)容因各人理解不同,可能會有所偏差贮尖,歡迎朋友們聯(lián)系我討論笛粘。 文中所有內(nèi)...
    珍此良辰閱讀 11,898評論 23 111
  • 【背景】 Action 發(fā)出以后,Reducer 立即算出 State湿硝,這叫做同步薪前。Action 發(fā)出以后,過一段...
    南慕瑤閱讀 642評論 0 0
  • 人活一世 苦難挫折在所難免 過得去的 過不去的 唯有自己親身承受 無法救贖 也無人能替 不必怨艾 不必悲傷 即無感...
    影子詩人閱讀 274評論 0 0