解析Koa2核心原理(手写KOA框架并解析)

解析Koa2核心原理(手写KOA框架并解析)

前言:
相对于express框架,koa框架只是提供了async/await 的语法应用,大致上逻辑是相同的!

文章主要分为三个部分:

  1. koa2创建服务
  2. async/await 语法
  3. 自己写个koa2

一:koa2
使用koa2创建服务

/**
 * koa2 中间件原理
 *1. app.use 先将注册的中间件收集起来
 *2.实现next。上一个通过next实现触发执行下一个,
 * 等await后面的的函数执行完了在执行剩下的语句
 */
const Koa = require('koa');
const app = new Koa();

// 注册中间件

// logger
app.use(async (ctx, next) => {
  await next();
  console.log('第一个中间件 结束')
});

app.use(async (ctx, next) => {
  await next();
  console.log('第二个中间件 结束')
});

// response
app.use(async ctx => {
  ctx.body = 'Hello World';
  console.log('第三个中间件 结束')
});


//监听
app.listen(8000);

通过以上代码可以知道,我们先执行第一个中间件,遇到next呢,然后去执行第二个中间件,等后面的中间件都执行ok后,await解禁,执行第一个中间件的剩下的语句

二: async/await 语法
通常在异步的时候,我们都会使用Promise来,但是了多层的嵌套出现问题,那么如何让异步“同步化”?这里是使用 async/await的语法,当然,返回的是promise对象


/**
 * async timeout(){
 *   return "hello world"
 *   throw new Error('rejected');
 * }
 *
 * 其 也是函数,所以,直接调用,但是,返回的是promise对象
 *timeout()  =====>promise
 *
 * 如果有正确的返回值,那么就调用promise.solve(data)
 * 如果返回错误信息, promise.reject(data)
 *
 * 我们想要在里面执行异步函数读取数据,
 *  await promise
 *  为了防止错误,一般我们会try catch 包裹
 */

三:自己写KOA2框架

const http = require('http');


class IKoa {
  constructor() {
    this.middlewareList = [];
  }

  /**
   * 收集 async中间件
   */
  use(fn){
      this.middlewareList.push(fn)
  }


  //创建上下文,组合相关的请求来和去的数据
  createContext(req,res){
    const ctx ={
      req,
      res
    }
    ctx.body = (data) => {
      let _d = data;
      if(typeof _d != 'string'){
        _d = JSON.stringify(_d)
      }
      res.end(_d)
    }
    return ctx;
  }

  //组合中间件,定义next方法
  compose(middlewareList){
    return function(ctx){
      // ctx.body({
      //   name:"a"
      // })
       function next(i) {
              //取出一个中间件
              const fn = middlewareList[i]
              if(fn){
                //next.bind(null,i+1)  = = next() 执行下一个中间件
                
                //这里也就是执行中间件函数	dispatch相当于next
                fn(ctx, next.bind(null, i + 1))  // promise
              }
        }
        //先执行第一个
        return next(0)
    }
  }
  /**
   * 上下文
   * @param  {[type]}   ctx
   * @param  {Function} fn  第一个中间件
   * @return  fn 这里返回一个fn
   */
  handleRequest(ctx,fn){
      return fn(ctx)
  }

  callback(){
    //获取第一个中间件
    const fn = this.compose(this.middlewareList)
    return (req,res) => {
        const ctx = this.createContext(req,res);
        //这里返回第一个中间件,作为callback的返回
        return this.handleRequest(ctx,fn)
    }
  }

  listen(...agrus){
    //这里的核心,callback 返回是执行的第一个中间件,通过第一个中间件去next下一个中间件
    const server = http.createServer(this.callback());
    server.listen(...agrus)
  }
}
module.exports = IKoa

通过以上代码,可以看出,callback返回的是第一个中间件的函数的组装函数,在这个组装函数里面先执行自身,其参数是ctx上下文,和下一个中间件函数,其实next也就是下一个中间件函数,那么执行next就相当于执行下一个中间件,当然,返回的是Promise,那么就可以用await接收

测试使用:

const Koa = require('./i-koa');
const app = new Koa();

app.use( async (ctx, next) => {
  // ctx.body("111")
  next()
  console.log("111");
})
app.use( async (ctx, next) => {
  ctx.body("222")

})

app.listen(9000,()=>{
  console.log("启动了");
})


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值