express和koa框架他们的核心其实都是中间件,但是事实上他们的中间件的执行机制是不同的,特别是针对某个中间件中包含异步操作时,所以,接下来我们再来研究一下express和koa中间件的执行顺序问题
首先我们先实现一个案例:
- 在middleware1中,在req.message中添加一个字符串 aaa;
- 在middleware2中,在req.message中添加一个 字符串bbb;
- 在middleware3中,在req.message中添加一个 字符串ccc;
- 当所有内容添加结束后,在middleware1中,通过res返回最终的结果;
1. 我们先来看express和koa分别同步实现
express同步实现:
const middleware1 = (req, res, next) => {
req.message = "aaa";
next();
res.end(req.message);
}
const middleware2 = (req, res, next) => {
req.message += "bbb";
next();
}
const middleware3 = (req, res, next) => {
req.message += "ccc";
}
最后返回的结果为:aaabbbccc
koa同步实现:
const middleware1 = (ctx, next) => {
ctx.message = "aaa";
next();
ctx.body = ctx.message;
}
const middleware2 = (ctx, next) => {
ctx.message += "bbb";
next();
}
const middleware3 = (ctx, next) => {
ctx.message += "ccc";
}
最后返回的结果也是为: aaabbbccc
其实express和koa同步实现没有什么区别,都是从上往下执行,当执行到next的时候,会将控制权交给下一个中间件,直到下一个中间件不再执行 next() 后,将会沿路折返,将控制权依次交还给前一个中间件,当交还到第一个中间件res.end时候,req.message里面就为'aaabbbccc'。
2. 再来看express和koa分别异步实现
express异步实现:
const middleware1 = async (req, res, next) => {
req.message = "aaa";
await next();
res.end(req.message);
}
const middleware2 = async (req, res, next) => {
req.message += "bbb";
await next();
}
const middleware3 = async (req, res, next) => {
const result = await axios.get('http://123.207.32.32:9001/lyric?id=167876');
req.message += result.data.lrc.version;
}
最后返回的结果为:aaabbb
koa异步实现:
const middleware1 = async (ctx, next) => {
ctx.message = "aaa";
await next();
ctx.body = ctx.message;
}
const middleware2 = async (ctx, next) => {
ctx.message += "bbb";
await next();
}
const middleware3 = async (ctx, next) => {
const result = await axios.get('http://123.207.32.32:9001/lyric?id=167876');
ctx.message += result.data.lrc.version;
}
最后返回的结果为:aaabbb26 // '26'为异步取到的数据
可以看到express和koa执行异步操作是有很大区别的,其中的根本原因是next实现的机制不同。在express中next内部的操作都是同步的,不管下一个中间件是否有异步操作,所以加上await也没有意义;而在koa中next返回的是Promise可以包含异步操作,所以可以加上await使其变为同步执行最后拿到请求的结果。