mini-koa的实现

161 阅读2分钟

koa主要做的就是api优雅化以及它的洋葱圈模型

首先根据我们使用koa时,我们会先new 一个实例然后use注册事件,listen去监视端口,所以我们可以先写一个如下的类

const http = require('http') 
class MyKoa {
  use(callback){
    this.callback = callback
  }
  listen(...args){
    const server = http.createServe((req,res) => {
       this.callback()
    })
    server.listen(...args)
  }
}

将req,res挂载在ctx上

将之前http的api优雅化

这边没有跟vue里通过递归对象然后object.defineProperty实现主要原因是因为他的属性是固定的,不像vue里data的属性值是不固定的

//context.js
module.exports = {
  get body(){
    return this.res.body
  }
  set body(val){
    this.res.body = val
  }
  get url(){
    return this.req.url
  }
  get method(){
    return this.res.method
  }
  ......
}
//request.js
module.exports = {
  get method(){
    return this.request.method
  }
  set methods(val){
     this.request.method = val.toUpperCase()
  }
  get url(){
     return this.request.url
  }
  .....
}
//response.js
module.exports = {
  get body(){
    return this.response._body
  }
  set body(val){
    this.response._body = val 
  }
  .....
}

用Object.create创建对象

因为需要将http里的res和req 传入进行对象继承,由于{...obj}运算符只能将对象进行浅拷贝,JSON.parse(JSON.stringify(obj))会深拷贝,但是无法继承源对象里的get,set方法,所以这边用object.create(obj)进行创建。

浅拷贝深拷贝get set方法
结构赋值
JSON.parse(JSON.stringify)
Object.create
const http = require('http') 
const request = require('./request.js')
const response = require('./response.js')
const conext = require('./context.js')
class MyKoa {
  use(callback){
    this.callback = callback
  }
  listen(...args){
    const server = http.createServe((req,res) => {
       const ctx = this.createContext(req,res)
       this.callback()
    })
    server.listen(...args)
  }
  createContext(req,res){
    const ctx = Object.create(context)
          ctx.request =Object.create(request)
          ctx.response = Object.create(response)
          ctx.req = ctx.request.req = req
          ctx.res = ctx.response.req = res
    return ctx
  }
}

洋葱圈模型的实现

实现聚合函数处理中间件

async function f1(next){
  console.log(1)
  await next()
  console.log('我执行完啦 f1')
}
async function f2(next){
  console.log(2)
  await delay(2000)
  await next()
  console.log('我执行完啦 f2')
}
async function f3(next){
  console.log(3)
  await next()
}
function delay(time){
   return new Promise((resolve) => {
     setTimeout(() => resolve(),time)
   })
}
//聚合函数 
function compose(middleware){
  return function(){
   return dispatch(0)
   function dispatch(i){
     const fn = middleware[i]
     if(!fn) return Promise.resolve() //当不是函数时候不能直接结束要返回个promise
     return Promise.resolve(fn(function next(){
      return dispatch(i+1) 
     }))//next函数本质就是下一个要执行的函数
   }
 }
}

将copmose函数应用在koa里

const http = require('http') 
const request = require('./request.js')
const response = require('./response.js')
const context = require('./context.js')
class MyKoa{
  constructor(){
    this.middleWares = []
  }
  use(middleWare){
    this.middleWares.push(middleWare)
  }
  listen(...args){
    const server = http.createServer(async(req,res) => {
       const ctx = this.createContext(req,res) //将req,res挂载在ctx
       const fn = this.compose(this.middleWares)
       await fn(ctx)
       res.end(ctx.body)
    })
    server.listen(...args)
  }
  createContext(req,res){
    const ctx = Object.create(context)
          ctx.request =Object.create(request)
          ctx.response = Object.create(response)
          ctx.req = ctx.request.req = req
          ctx.res = ctx.response.res = res
    return ctx
  }
  compose(middleware){
    return function(ctx){
     return dispatch(0)
     function dispatch(i){
       const fn = middleware[i]
       if(!fn) return Promise.resolve() //当不是函数时候不能直接结束要返回个promise
       return Promise.resolve(fn(ctx,function next(){
         return dispatch(i+1) 
       }))//next函数本质就是下一个要执行的函数
     }
   }
  }
}
module.exports = MyKoa