美文网首页
Koa2核心原理

Koa2核心原理

作者: 谢玉胜 | 来源:发表于2020-07-22 19:05 被阅读0次

    解析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("启动了");
    })
    
    
    

    相关文章

      网友评论

          本文标题:Koa2核心原理

          本文链接:https://www.haomeiwen.com/subject/rkitlktx.html