koa原理实现简析

127 阅读1分钟

koa用法:

const Koa =require('koa');
const app=new Koa()
app.use((ctx,next)=>{
  ctx.body={
      name:123
  }
})
app.listen(3000,()=>{
     console.log('koa...')
})

分析

1.ctx涉及上下文、gettersetter
2.next涉及合成函数compose

request.js

module.exports = { 
    get url() {
      return this.req.url; 
    },
    get method(){
      return this.req.method.toLowerCase() 
    }
 };

response.js

module.exports = { 
    get body() {
       return this._body; 
    },
    set body(val) { 
      this._body = val;//内部变量
    } 
};

context.js

module.exports = { 
    get url() {
      return this.request.url; 
    },
    get body() {
      return this.response.body;
    },
    set body(val) {
      this.response.body = val; 
    },
    get method() {
       return this.request.method
    } 
};

compose.js

洋葱模型,中间件
function compose(middlewares){
  return function(ctx){
    return dispatch(0);
    function dispatch(i){
       let fn=middlewares[i]
       if(!fn){Promise.resolve()}
       Promise.resolve(
         fn(ctx,function next(){
             return dispatch(i+1)
         })
       )
    }
  }
}

koa.js

class Kkb{
    constructor(){
        this.middlewares = []
    }

    listen(...args){
        const server=http.createServer(async (req,res)=>{
            // 创建上下文
            let ctx = this.createContext(req, res);
            const fn = this.compose(this.middlewares)
            await fn(ctx)
            res.end(ctx.body);
        })

        server.listen(...args)
    }

    use(middleware){
     this.middlewares.push(middleware)
    } 

    createContext(req,res){
       const ctx=Object.create(context)//里面用到了this.request
       ctx.request=Object.create(request)//里面用到了原生的req
       ctx.response=Object.create(response)
       //以上两部把上下文和request连起来

       ctx.req=ctx.request.req=req//想下图,连接剩下的四条线
       ctx.res=ctx.response.res=res

       return ctx
    }
    
    //合成函数
    compose(middlewares){
        return function(ctx){
            return dispatch(0);
            function dispatch(i){
               let fn=middlewares[i]
               if(!fn){Promise.resolve()}
               Promise.resolve(
                 fn(ctx,function next(){
                     return dispatch(i+1)
                 })
               )
            }
        }
    }
}

通过以上就基本上实现了koa

上下文连接的图解: