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