解讀koa-compose

上一講我們講到 koa-router 的實現,今天我們講講 koa-compose格郁,compose是將多個函數合并成一個函數(形如: g() + h() => g(h())),koa-compose則是將 koa/koa-router 各個中間件合并執(zhí)行独悴,結合 next() 就形成了洋蔥式模型

image

有同學可能不了解為何是洋蔥式模型例书,接下來我們改造下官方test用例,打出相應 log 應該就清楚了

it.only('should work', async () => {
    const arr = []
    const stack = []

    stack.push(async (context, next) => {
      arr.push(1)
      await wait(1)
      console.log(1)
      await next()
      console.log(1, 1)
      await wait(1)
      arr.push(6)
    })

    stack.push(async (context, next) => {
      arr.push(2)
      await wait(1)
      console.log(2)
      await next()
      console.log(2, 2)
      await wait(1)
      arr.push(5)
    })

    stack.push(async (context, next) => {
      arr.push(3)
      await wait(1)
      console.log(3)
      await next()
      console.log(3, 3)
      await wait(1)
      arr.push(4)
    })
    const a = compose(stack)
    console.log('result-->>>>>>', a)
    await compose(stack)({})
    expect(arr).toEqual(expect.arrayContaining([1, 2, 3, 4, 5, 6]))
  })

結果是1, 2, 3, 33, 22, 11刻炒,可以看出先按順序執(zhí)行 stack 數組中每個中間件 next 前的代碼决采,之后倒序執(zhí)行 next 后的代碼,相當于一根牙簽橫穿洋蔥坟奥,先從外到內织狐,再從內到外,所以叫做洋蔥模型筏勒。

koa-compose 的代碼只有不夠50行移迫,細讀確實是一段很精妙的代碼,而實際核心代碼則是這一段:

return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, function next () {
          return dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }

雖然短管行,但是之中使用了4層 return厨埋,初看會比較繞,我們只看第3捐顷,4層 return荡陷,這是返回實際的執(zhí)行代碼鏈

return Promise.resolve(fn(context, function next () {
          return dispatch(i + 1)
        }))

以下分解參照跨入Koa2.0雨效,從Compose開始這篇文章,說得挺好的废赞。

這里嘗試用3個中間件進行 compose徽龟,并逐步分解執(zhí)行過程
  • 第一次,此時第一個中間件被調用唉地,dispatch(0)据悔,展開:
Promise.resolve(function(context, next){
    //中間件一第一部分代碼
    await/yield next();
    //中間件一第二部分代碼
}());

很明顯這里的next指向dispatch(1)耘沼,那么就進入了第二個中間件极颓;

  • 第二次,此時第二個中間件被調用群嗤,dispatch(1)菠隆,展開:
Promise.resolve(function(context, 中間件2){
    //中間件一第一部分代碼
    await/yield Promise.resolve(function(context, next){
        //中間件二第一部分代碼
        await/yield next();
        //中間件二第二部分代碼
    }())
    //中間件一第二部分代碼
}());

很明顯這里的next指向dispatch(2),那么就進入了第三個中間件狂秘;

  • 第三次骇径,此時第二個中間件被調用,dispatch(2)者春,展開:
Promise.resolve(function(context, 中間件2){
    //中間件一第一部分代碼
    await/yield Promise.resolve(function(context, 中間件3){
        //中間件二第一部分代碼
        await/yield Promise(function(context){
            //中間件三代碼
        }());
        //中間件二第二部分代碼
    })
    //中間件一第二部分代碼
}());

此時中間件三代碼執(zhí)行完畢既峡,開始執(zhí)行中間件二第二部分代碼,執(zhí)行完畢碧查,開始執(zhí)行中間一第二部分代碼,執(zhí)行完畢校仑,所有中間件加載完畢忠售。

總結

koa-compose 巧妙的運用了 compose 的特性,結合 async await 中 next 的等待執(zhí)行迄沫,形成了洋蔥模型稻扬,我們可以利用這一特性在 next 之前對 request 進行處理,而在 next 之后對 response 進行處理(例如 error 處理)

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末羊瘩,一起剝皮案震驚了整個濱河市泰佳,隨后出現的幾起案子,更是在濱河造成了極大的恐慌尘吗,老刑警劉巖逝她,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異睬捶,居然都是意外死亡黔宛,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門擒贸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臀晃,“玉大人觉渴,你說我怎么就攤上這事』胀铮” “怎么了案淋?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長险绘。 經常有香客問我踢京,道長,這世上最難降的妖魔是什么隆圆? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任漱挚,我火速辦了婚禮,結果婚禮上渺氧,老公的妹妹穿的比我還像新娘旨涝。我一直安慰自己,他們只是感情好侣背,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布白华。 她就那樣靜靜地躺著,像睡著了一般贩耐。 火紅的嫁衣襯著肌膚如雪弧腥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天潮太,我揣著相機與錄音管搪,去河邊找鬼。 笑死铡买,一個胖子當著我的面吹牛更鲁,可吹牛的內容都是我干的。 我是一名探鬼主播奇钞,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼澡为,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了景埃?” 一聲冷哼從身側響起媒至,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谷徙,沒想到半個月后拒啰,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡完慧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年图呢,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛤织,死狀恐怖赴叹,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情指蚜,我是刑警寧澤乞巧,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站摊鸡,受9級特大地震影響绽媒,放射性物質發(fā)生泄漏。R本人自食惡果不足惜免猾,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一是辕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猎提,春花似錦获三、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至伞租,卻和暖如春贞谓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葵诈。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工裸弦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人作喘。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓理疙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親徊都。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內容