结论:
Koa2 支持了 async/await 的写法,避免了 express 的 callback 地狱回调的问题,也就更好的利于维护。它使用了洋葱模型,更能控制流程。
对比
Express 和 Koa 的作者都是同一个人 ****TJ Holowaychuk 大神。核心都是通过中间件的方式实现。
由于 Koa 出现的比较晚,就用了更新的 js 语法,例如 async/await, 也借用此采用 洋葱模型。
使用上对比:
会发现 Koa2 使用更简洁(主要还是 async/await 使用更舒服)
// 以获取数据为例
// Express
router.post('/update', function (req, res, next) {
const id = req.query.id;
getData(id).then(data => {
res.json(data);
}).catch((e) => {
res.json({ code:-1, msg: 'error' })
});
});
// Koa2
router.post('/update', loginCheck, async function (ctx, next) {
const id = ctx.query.id;
try {
const data = await getData(id);
ctx.body = data;
} catch (e) {
ctx.body = { code:-1, msg: 'error' };
}
})
洋葱模型
如图:
中间件使用 next() 移交控制权给下一个,直到没有再调用的中间件了,再沿路折回,逐步将控制权重新移交会上一个,(其实就是入栈出栈)
从使用上来说,如下,express 可以认为是调用(触发下一个执行,无法监听到异步代码执行结束),而 koa2 可以认为是等待(等下一个真正执行完,包括异步代码)
// Express
const express = require('express')
const app = express()
app.use((req, res, next) => {
// do some thing
next();
});
app.use((req, res, next) => {
// do some other thing
next();
});
// Koa2
const express = require('koa')
const app = express()
app.use(async (ctx, next) => {
// do some thing
await next();
// do some thing
});
app.use(async (ctx, next) => {
// do some other thing
await next();
// do some other thing
});
可能看起来没啥区别,但举一个例子,想统计接口的耗时,这个时候如果用 express,在第一个中间件记录开始时间,因为调用 next 是同步代码,并调用下一个中间件,而下一个中间件再去觉得是否调用下一个,而上一个又无法直到下一个中间件是否结束了(只能知道同步的逻辑执行完成了,但异步逻辑没有办法传回调用方),所以实现需要使用另外的方式(例如需要监听 res 的 finish 时间,来作为结束时间),但 Koa2 应该洋葱模型,一定会回来,所以就很好实现,在 await next() 前后记录开始、结束时间即可。
// Express for Log Time
app.use((req, res, next) => {
const startTime = Date.now();
const recordTime = () => {
const costTime = Date.now() - startTime;
console.log(costTime);
};
res.once('finish', recordTime);
return next();
});
// Koa2 for Log Time
app.use(async (ctx, next) =>{
const startTime = Date.now();
await next();
const costTime = Date.now() - startTime;
console.log(costTime);
});