之前其實寫過一篇express和koa的對比, 可是後來發現裏面有很多謬誤. 因此一直惦記着糾正一下以前的錯誤, 尤爲關於中間件部分的對比.數據庫
這裏的express就拿更加簡單的connect代替express
一般咱們都說connect的中間件模型是線性的, 也就是一個一個往下執行的, 以下圖:app
這麼說固然是沒錯的, 可是當咱們執行下面代碼的時候可能會有那麼一點小小的困惑:koa
const connect = require('connect') const app = connect() app.use(function m1 (req, res, next) { console.log('m1') next() console.log('m1 end') }) app.use(function m2 (req, res, next) { console.log('m2') next() console.log('m2 end') }) app.use(function m3 (req, res, next) { console.log('m3') res.end('hello') }) app.listen(8080)
當咱們訪問http://127.0.0.1:8080
的時候, 控制檯會打印以下:異步
m1 m2 m3 m2 end m1 end
這麼個結果跟咱們上面的模型彷佛有點出入, 不是說線性的嗎, 爲何next後面的代碼還會繼續執行? 固然這個咱們再以前已經有過結論了, 有興趣的能夠詳細瞧瞧, 咱們如今直接拿來結果, connect的中間件模型僞代碼表示以下:async
http.createServer(function (req, res) { m1 (req, res) { m2 (req, res) { m3 (req, res) {} } } })
能夠看到就是一層一層嵌套的回調, 那麼再把咱們以前有點疑問的代碼簡化一下:函數
http.createServer(function (req, res) { console.log('m1') m1 (req, res) { console.log('m2') m2 (req, res) { m3 (req, res) { console.log('m3') res.end('hello') } } console.log('m2 end') } console.log('m1 end') })
千萬別被上面的回調繞暈了, 就是很簡單的回調函數, 一切都解釋的通了: 即便res.end
以後, 咱們的代碼仍是要繼續往下走的, 能夠這麼說connect的中間件其實也是洋蔥形的, 可是由於做爲同步代碼, 通常不回這麼作罷了, 那麼上面咱們能夠重現描述一下connect的中間件模型了:源碼分析
一樣咱們再Koa源碼分析, 也是說過Koa的中間件模型: 洋蔥形
post
如下面代碼爲例:ui
const Koa = require('koa') const app = new Koa() app.use(async function m1 (ctx, next) { console.log('m1') await next() console.log('m1 end') }) app.use(async function m2 (ctx, next) { console.log('m2') await next() console.log('m2 end') }) app.use(async function m3 (ctx) { console.log('m3') ctx.body = 'hello' }) app.listen(8080)
訪問服務, 輸出:
m1 m2 m3 m2 end m1 end
emm 貌似跟connect沒差異, 以前看過一篇文章, 實驗到這裏獲得了一個koa和express的中間件模型沒差異的結論, 包括我也是很迷惑, 固然是有差異的, 結論後面講. 一樣這裏直接拿出koa中間件的簡化模型:
Promise.resolve(async m1 () { console.log(m1) await Promise.resolve(async m2 () { console.log(m2) await Promise.resolve(async m3 () { console.log(m3) ctx.body = 'xxx' }) console.log(m2 end) }) console.log(m1 end) })
咱們知道async/await
的做用是'同步化'異步操做(看上去如此, 其實不是, 可是咱們不須要去管), 那這裏的Promise理所固然的被'同步'了, 也就是說console.log(m3 end)
的一切異步操做均可以'同步化'.
說出結論以前咱們其實能夠想一下, 既然connect的中間件也是洋蔥形的, 那麼跟koa同樣的用法彷佛也沒啥毛病, 那麼我來設想一下, 咱們的服務須要取數據庫裏的的一個用戶假設是getUser
吧, getUser
固然是異步的. 分別來看看connect和koa的作法吧:
// connect app.use(function (req, res) { getUser(user => res.end(user)) }) // Koa app.use(async (ctx) => { const user = await getUser() ctx.body = user })
固然這麼看彷佛沒啥差異. 那直接給出結論吧(憋): connect的中間件是同步, 不會'等'其餘異步操做, koa則能夠'等'異步操做. 固然你不等也沒啥問題.
有啥問題能夠互相交流哈.