一篇文章瞭解洋蔥圈模型——看了就忘不掉的那種

洋蔥圈這個概念起源於Koa,因爲其靈活、易擴展,目前已經普遍的流傳開來。例如umi-request的洋蔥中間件機制,阿里內部的eaas封裝(egg as a service),都用到了洋蔥圈的概念。關於洋蔥圈,其實論壇裏也有不少的源碼閱讀文章,但大部分都直接講源碼,形成了必定的理解困難——包括我本身常常也是這樣,難以把握住核心理念;所以,本文會採起 提問題,定方案,而後帶着方案回頭去看源碼的方式來剖析洋蔥圈,但願你們能看過就懂,懂了就不會忘。

1. 洋蔥圈模型

無論怎麼聊,這張圖仍是要放一下的。能夠看到,每一箇中間件都是一個洋蔥圈。每次當有一個請求進入的時候,每一箇中間件都會被執行兩次。例以下面的例子:
image.pngsegmentfault

const Koa = require("koa")

const app = new Koa()

// 中間件A
app.use(async (ctx, next) => {
    console.log("A1")
    await next()
    console.log("A2")
});
// 中間件B
app.use(async (ctx, next) => {
    console.log("B1")
    await next()
    console.log("B2")
});
// 中間件C
app.use(async (ctx, next) => {
    console.log("C1")
    await next()
    console.log("C2")
});

app.listen(3000);

// 輸出
// A1 -> B1 -> C1 -> C2 -> B2 -> A2

2.核心理念

首先,咱們來分析一下:數組

每一箇中間件都接收了一個next參數,在next函數運行以前的中間件代碼會在一開始就執行,next函數以後的代碼會在內部的中間件所有運行結束以後才執行。網絡

要想達到上面洋蔥圈的運行效果,咱們須要作什麼呢?app

  1. 首先咱們要知道當前中間件的數組集合
  2. 而後構建一個組合方法,對這些中間件按照洋蔥的結構進行組合,並執行

咱們帶着這樣的一個思路,再回頭來看Koa是如何實現的:koa

  1. this.middleware是中間件集合的數組
  2. koa-compose模塊的compose方法用來構建執行順序

完美!下面只須要具體分析一下它們分別作了什麼就能夠了async

// middleware用來保存中間件
app.use = (fn) => {
    this.middleware.push(fn)
    return this
}

// compose組合函數來規定執行次序
function compose (middleware) {
  // context:上下文,next:傳入的接下來要運行的函數
  return function (context, next) {
    function dispatch (i) {
      index = i
      // 中間件
      let fn = middleware[i]
      if (!fn) return Promise.resolve()
      try {
        // 咱們這邊假設和上文中的例子同樣,有A、B、C三個中間件
        // 經過dispatch(0)發起了第一個中間件A的執行
        // A中間件執行以後,next做爲dispatch(1)會被執行
        // 從而發起了下一個中間件B的執行,而後是中間件C被執行
        // 全部的中間件都執行了一遍後,執行Promise.resolve()
        // 最裏面的中間件C的await next()運行結束,會繼續執行console.log("C2")
        // 整個中間件C的運行結束又觸發了Promise.resolve
        // 中間件B開始執行console.log("B2")
        // 同理,中間件A執行console.log("A2")
        return Promise.resolve(fn(context, () => {
          return dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
    return dispatch(0)
  }
}

3. 總體回顧

Koa利用了在中間件中間傳入next參數的方法,再結合middleware中間件數組和compose組合函數,構建了洋蔥圈的中間件執行結構。這也是爲何洋蔥圈中間件機制能夠運行起來的緣由。函數

洋蔥圈的代碼並不複雜,可是這種提出問題,帶着解決思路去看代碼的方式,但願能給你們一點啓發。ui

4. 參考文章

1.《淺析koa的洋蔥模型實現
2.《Koa2 洋蔥模型 —— compose 串聯中間件的四種實現
3.《umi-request 網絡請求之路this

相關文章
相關標籤/搜索