koa中的中间件分析:
输出的顺序模拟了koa的洋葱模型,借着输出结果,分析下输出下边结果的原因:
使用async和await,说明中间件参数函数是异步函数,因为里边的next( ) 是异步的 ( next()相当于下一个中间件 ),输出2的时机是:必须等到下一个中间件执行完毕后,才能输出2。
const Koa = require('koa')
const app = new Koa()
// 洋葱模型: 执行顺序是 1 3 4 2
app.use( async (ctx, next) => {
console.log('1')
await next()
console.log('2')
})
app.use( async (ctx, next) => {
console.log('3')
await next()
console.log('4')
})
app.listen(3000)
其实,next返回的是一个Promise对象,之所以里边为undefined,因为下一个中间件没有返回值。
// 洋葱模型: 执行顺序是 1 3 4 Promise{undefined} 2
app.use((ctx, next) => {
console.log('1')
const nextPromise = next()
console.log(nextPromise)
console.log('2')
})
app.use( async (ctx, next) => {
console.log('3')
// await next()
console.log('4')
})
改写
所以上边使用的sync 和await写法,可以改成如下:
// 洋葱模型: 执行顺序是 1 3 4 Promise{undefined} 2
app.use((ctx, next) => {
console.log('1')
const nextPromise = next()
nextPromise.then((res) => {
console.log('res', res)
console.log('2')
})
})
app.use( async (ctx, next) => {
console.log('3')
// await next()
console.log('4')
})
tips:
1、如果上边代码不加async,next() 的返回结果仍然是一个Promise对象,原因koa框架内部已经处理。
2、为什么每个next() 前需要加上await:
保证代码的执行顺序,也就是"洋葱模型的执行顺序"
// '1' -> '3' -> '5' -> '6' -> '4' -> '2'
app.use(async (ctx, next) => {
console.log('1')
await next()
console.log('2')
})
app.use( async (ctx, next) => {
console.log('3')
await next()
console.log('4')
})
app.use(async (ctx, next) => {
console.log('5')
await next()
console.log('6')
})
3、当使用app.use()注册一个中间件时,中间件必须为一个函数,在源码中也能看到:
4、use 方法最终返回的还是一个app实例,所以注册中间件的时候可以链式调用:
app.use().use().use()