今日在学习koa的过程中遇到了异步不返回结果的情况, 如下
app.use((ctx, next) => {
new Promise(resolve => {
setTimeout(() => {
ctx.body = 'hello'
resolve()
}, 1000)
})
})
想正确返回也很简单,检查前面的中间件,保证是await next()
或者是return next()
// 前面的中间件
app.use(async (ctx, next) => await next())
// 或者
app.use((ctx, next) => return next())
// 然后
app.use((async ctx, next) => {
await new Promise(resolve => {
setTimeout(() => {
ctx.body = 'hello'
resolve()
}, 1000)
})
// 或者在这里 return new Promise(...) 也是可以的
})
一开始我困惑的是即然这里都不需要返回值,返回的也是空值,那么await
加与不加又有什么差别呢?
直到我了解了koa的源码后才恍然大悟。
Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))
,当中间件走完,.then
中的ctx.body能获取到正确值时,才会返回相应的内容,否则就是404的情况了。
- 添加中间件
function task0 (ctx, next) {
return next()
}
function async task1 (ctx, next) {
await next()
}
function async task3 (ctx, next) {
await new Promise(resolve => {
setTimeout(() => {
ctx.body = 'hello'
}, 1000)
})
}
app.use(task0);
app.use(task1);
app.use(task2);
- 中间件的compose处理(洋葱模型)
function compose (middleware) {
// if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
// for (const fn of middleware) { if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')}
return function (context, next) {
let index = -1
return dispatch(0)
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
当一个http请求过来时的简易代码:
// dispatch(0)
return Promise.resolve(task0(ctx, dispatch_1))
function task0 (ctx, dispatch_1) {
return dispatch_1()
}
function dispatch_1 () {
return Promise.resolve(task1(ctx, dispatch_2))
}
async function task1 (ctx, dispatch_2) {
await dispatch_2()
}
function dispatch_2 () {
return Promise.resolve(task2(ctx, dispatch_3))
}
async function task2 () {
await new Promise(resolve => {
setTimeout(() => {
ctx.body = 'hello'
resolve()
}, 1000)
})
}
function dispatch_3 () {};
换个方式,这样看应该比较好理解:
var ctx = {body: null}
function task0 () {
return Promise.resolve(
Promise.resolve(task1())
)
};
async function task1 () {
await Promise.resolve(
await new Promise(resolve => {
setTimeout(() => {
ctx.body = 'hello'
resolve()
}, 1000)
})
)
};
Promise.resolve(task0(ctx)).then(() => {
console.log('res', ctx.body)
handleResponse(ctx)
});
// res: 'hello'
如果task0 即没有return next()
(返回新的Promise对象)又没有await next()
,那么它会马上到handleResponse(ctx)
,而此时ctx.body='hello'
还没有执行。
所以与express不同,koa里面的next用await next()
或者return next()
。