• 作者:老汪软件技巧
  • 发表时间:2024-09-05 04:01
  • 浏览量:

koa是什么

Koa是一个用于构建Web应用和API的轻量级、模块化的Node.js框架。它帮助开发者通过async函数更好地错误处理和更清晰地组织代码。Koa 的中间件机制采用了一种被称为“洋葱模型”的设计模式。

洋葱模型是什么

Koa的洋葱模型是指其中间件的执行方式。

举个例子,结果为1342

当中间件执行到一定程度,调用next,就会进入下一个中间件的执行,当下一个中间件执行完毕然后再回到上一个中间件执行next后的部分,是不是有递归的感觉了?

const Koa = require('koa');
const app = new Koa();
// 中间件1
app.use((ctx, next) => {
    console.log(1);
    next();
    console.log(2);
});
// 中间件 2 
app.use((ctx, next) => {
    console.log(3);
    next();
    console.log(4);
});
app.listen(8000, () => {
    console.log(`Server is starting in 8000`);
});

当一个请求进入时,它会依次穿过每一层中间件(从外到内),每层中间件都可以做一些预处理(如日志记录、身份验证等)。当达到最内部的中间件时,开始处理实际的业务逻辑,之后再通过调用next()方法逐层返回(从内到外),在返回的过程中可以进行响应的构造(如设置响应头、发送响应体等)。

koa结合async、await方式,帮助开发者通过async函数更好地错误处理和更清晰地组织代码。利用这种方式和洋葱模型,我们可以做什么?

app.use(async(ctx, next) => {
  const start = new Date();
  await next();
  const delta = new Date() - start;
  console.log (`请求耗时: ${delta} MS`);
  console.log('拿到上一次请求的结果:', ctx.state.baiduHTML);
})
app.use(async(ctx, next) => {
  // 处理 db 或者进行 HTTP 请求
  ctx.state.baiduHTML = await axios.get('http://baidu.com');
})

洋葱模型理论__洋葱模型的外层包括哪些内容

koa洋葱模型是怎么实现的?use方法

从上面的例子,我们能看到,每个组件,都被我们use、use...,事实上use就是维护了一个middleware中间件数组

  use(fn) {
    // ...
    // 维护中间件数组——middleware
    this.middleware.push(fn);
    return this;
  }

内部实现

listen方法就不多介绍了,事实上就是node中的http模块createServer创建服务,他接收回调函数callback

const Koa = require('koa');
const app = new Koa();
// 中间件1
app.use((ctx, next) => {
    console.log(1);
    next();
    console.log(2);
});
// 中间件 2 
app.use((ctx, next) => {
    console.log(3);
    next();
    console.log(4);
});
app.listen(8000, () => {
    console.log(`Server is starting in 8000`);
});

内部实现,其中compose函数就是洋葱模型的关键

  listen(...args) {
    debug('listen');
    // node http 创建一个服务
    const server = http.createServer(this.callback());
    return server.listen(...args);
  }
  callback() {
    // 返回值是一个函数
    const fn = compose(this.middleware);
    const handleRequest = (req, res) => {
      // 创建 ctx 上下文环境
      const ctx = this.createContext(req, res);
      return this.handleRequest(ctx, fn);
    };
    return handleRequest;
  }

因此我们接下来来看看,compose函数是怎么实现的

compose函数

理解了洋葱模型,我们就来看看,use维护了我们的middleware数组,然后conpose是如何将数组中的函数执行掉,并且顺序是135642的

// 实现koa的洋葱模型
// 中间件的执行,执行到一定程度调用next然后就会进入到下一个中间件的执行,一定程度执行next
// 又进入下一个中间件的执行,这个中间件的执行完毕然后回到上一个中间件的执行,上个中间件的执行完毕
// 再往上回,筷子穿洋葱的过程
let middleware = []
middleware.push((ctx, next) => {
    console.log(1);
    next()
    console.log(2);
})
middleware.push((ctx, next) => {
    console.log(3);
    next()
    console.log(4);
})
middleware.push((ctx, next) => {
    console.log(5);
    next()
    console.log(6);
})
let fn = compose(middleware)
fn()  // 1 3 5 6 4 2 
function compose(middleware) {
    return function fn(context, next) {
        return dispatch(0)
        function dispatch(i) {
            if (i > middleware.length - 1) return
            let fn = middleware[i]  // 取第一个函数
            if (i === middleware.length) fn = next  // 
            const nextFn = dispatch.bind(context, i + 1) // 取第二个函数
            const p = fn(context, nextFn)
            return p
        }
    }
}
// 1. 递归
// 2. 函数执行到next时要让下一个函数触发