起因
最近在學習koa的使用, 由于koa是相當基礎的web框架,所以一個完整的web應用所需要的東西大都以中間件的形式引入,比如koa-router, koa-view等。在koa的文檔里有提到:koa的中間件模式與express的是不一樣的,koa是洋蔥型,express是直線型,至于為什么這樣,網上很多文章并沒有具體分析。或者簡單的說是async/await的特性之類。先不說這種說法的對錯,對于我來說這種說法還是太模糊了。所以我決定通過源碼來分析二者中間件實現的原理以及用法的異同。
為了簡單起見這里的express用connect代替(實現原理是一致的)
用法
二者都以官網(github)文檔為準
connect
下面是官網的用法:
根據文檔我們可以看到,connect是提供簡單的路由功能的:
connect的中間件是線性的,next過后繼續尋找下一個中間件,這種模式直覺上也很好理解,中間件就是一系列數組,通過路由匹配來尋找相應路由的處理方法也就是中間件。事實上connect也是這么實現的。
app.use 就是往中間件數組中塞入新的中間件。中間件的執行則依靠私有方法 app.handle 進行處理,express也是相同的道理。
koa
相對connect,koa的中間件模式就不那么直觀了,借用網上的圖表示:
也就是koa處理完中間件后還會回來走一趟,這就給了我們更加大的操作空間,來看看koa的官網實例:
很明顯,當koa處理中間件遇到await next()的時候會暫停當前中間件進而處理下一個中間件,最后再回過頭來繼續處理剩下的任務,雖然說起來很復雜,但是直覺上我們會有一種隱隱熟悉的感覺:不就是回調函數嗎。這里暫且不說具體實現方法,但是確實就是回調函數。跟async/await的特性并無任何關系。
源碼簡析
connect與koa中間件模式區別的核心就在于next的實現,讓我們簡單看下二者next的實現。
connect
connect的源碼相當少加上注釋也就200來行,看起來也很清楚,connect中間件處理在于proto.handle這個私有方法,同樣next也是在這里實現的
刪掉混淆的代碼后 我們可以看到next實現也很簡潔。一個遞歸調用順序尋找中間件。不斷的調用next。代碼相當簡單但是思路卻很值得學習。
其中 done 是第三方處理方法。其他處理sub app以及路由的部分都刪除了。不是重點
koa
koa將next的實現抽離成了一個單獨的包,代碼更加簡單,但是實現了一個貌似更加復雜的功能
看著上面處理過的的代碼 有些同學可能還是會不明覺厲。
那么我們繼續處理一下:
這樣一來 程序更加簡單了 跟async/await也沒有任何關系了,讓我們看下結果好了
執行上面的程序我們可以發現依次輸出:
foo1
bar1
qux1
qux2
bar2
foo2
同樣是所謂koa的洋蔥模型,到這里我們就可以得出這樣一個結論:koa的中間件模型跟async或者generator并沒有實際聯系,只是koa強調async優先。所謂中間件暫停也只是回調函數的原因(在我看來promise.then與回調其實沒有什么區別,甚至async/await也是回調的一種形式)。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com