每天一个npm包:koa-connect

508 阅读2分钟

koa-connect相信有些早期写Koa2的童鞋比较熟悉,它的作用就是在Koa2中可以使用Express社区的中间件,起到了一个中转或者适配的作用。

那么接下来我们去看下源码是如何实现的。

源码

首先我们简单了解express常见的中间件用法有哪些?

app.get('/', [
  // 带有next回调、进入下一个中间件
  function (req, res, next) {
    fs.readFile('/maybe-valid-file', 'utf-8', function (err, data) {
      res.locals.data = data
      next(err)
    })
  },
  // 基本款、不带next回调
  function (req, res) {
    res.locals.data = res.locals.data.split(',')[1]
    res.send(res.locals.data)
  }
])

那么对应Koa2中间件长什么样呢?

// ctx、next
app.use(async (ctx, next) => {
  await next();
  const rt = ctx.response.get('X-Response-Time');
  console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

好了,这里记得提下在Koa中,next是一个包装的Promise。

那么接下来我们就去看下源码对应实现。

"use strict";
const noop = () => { };

// 不带next回调的express中间件包装函数
function noCallbackHandler(ctx, connectMiddleware, next) {
    // next => Koa2中间件函数
    // 可见express中间件的req、res与ctx.req、ctx.res一致
    connectMiddleware(ctx.req, ctx.res, noop);
    // 直接进入下一个Koa2中间件流程
    return next();
}

// 带next回调的express中间件包装函数
function withCallbackHandler(ctx, connectMiddleware, next) {
    // 返回Promise 符合Koa2中间件规范 await next
    return new Promise((resolve, reject) => {
        connectMiddleware(ctx.req, ctx.res, (err) => {
            // err为业务中抛出的error
            // 这里对err的处理 符合express error handing
            // https://www.expressjs.com.cn/guide/error-handling.html
            if (err)
                reject(err);
            else
                // 正常进入下一个中间件
                resolve(next());
        });
    });
}

// 暴露的方法
// connectMiddleware:中间件函数
function koaConnect(connectMiddleware) {
    // 根据connectMiddleware.length判断是否带next回调。
    // 但是如果你中间件函数使用的是arguments或者rest就会判断有问题。
    const handler = connectMiddleware.length < 3 ? noCallbackHandler : withCallbackHandler;
    // 最后返回的就是符合Koa2 中间件签名的函数
    return function koaConnect(ctx, next) {
        return handler(ctx, connectMiddleware, next);
    };
}
module.exports = koaConnect;

好了,今天就到这结束了,下期见。

ps:如果你对node也有兴趣,欢迎关注我公众号:xyz编程日记。