之前其實寫過一篇express和koa的對比, 可是後來發現裏面有很多謬誤. 因此一直惦記着糾正一下以前的錯誤, 尤爲關於中間件部分的對比.數據庫
這裏的express就拿更加簡單的connect代替express
一般咱們都說connect的中間件模型是線性的, 也就是一個一個往下執行的, 以下圖:bash
這麼說固然是沒錯的, 可是當咱們執行下面代碼的時候可能會有那麼一點小小的困惑:app
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
的時候, 控制檯會打印以下:koa
m1
m2
m3
m2 end
m1 end
複製代碼
這麼個結果跟咱們上面的模型彷佛有點出入, 不是說線性的嗎, 爲何next後面的代碼還會繼續執行? 固然這個咱們再以前已經有過結論了, 有興趣的能夠詳細瞧瞧, 咱們如今直接拿來結果, connect的中間件模型僞代碼表示以下:異步
http.createServer(function (req, res) {
m1 (req, res) {
m2 (req, res) {
m3 (req, res) {}
}
}
})
複製代碼
能夠看到就是一層一層嵌套的回調, 那麼再把咱們以前有點疑問的代碼簡化一下:async
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
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則能夠'等'異步操做. 固然你不等也沒啥問題.
有啥問題能夠互相交流哈.