Express VS Koa2, 为啥选择 KOA2

587 阅读2分钟

结论:

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' };
  }
})

洋葱模型

如图:

image.png

中间件使用 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);
});