实现简易Koa2

61 阅读1分钟

使用http模块

实现步骤

  1. 收集中间件middlewareList
class SimpleKoa2 {
  constructor(){
    this.middlewareList = []
  }
  use(fn){
    this.middlewareList.push(fn)
  }
}
  1. 监听端口listen
class SimpleKoa2 {
  /* ... */
  listen(...args){
    const server = http.createServer(this.callback())
    server.listen(...args)
  }
}
  1. 组合中间件实现next()原理
class SimpleKoa2 {
  /* ... */
  listen(...args) {
    const server = http.createServer(this.callback())
  }
  callback() {
    // 组装中间件
    const fn = this.compose(this.middlewareList)
    return (req, res) => {
      const ctx = this.createContext(req, res)
      return this.handleRequest(ctx, fn)
    }
  }
  compose(middlewares) {
    return (ctx) => {
      function dispatch(i) {
        const fn = middlewares[i]
        try {
          return Promise.resolve(fn(ctx, dispatch.bind(null, i + 1)))
        } catch (err){
          return Promise.reject(err)
        }
      }
      // 从第一个中间件开始
      return dispatch(0)
    }
  }
  // 组合 ctx
  createContext(req, res) {
    const ctx = { req, res }
    ctx.query = req.query
    return ctx
  }
  // 执行中间件
  handleRequest(ctx, fn) {
    return fn(ctx)
  }
}

总结

  • 收集所有使用的中间件

  • 核心: 实现next()执行所有匹配的中间件

const http = require('http)
class SimpleKoa2 {
  constructor() {
    this.middlewareList = []
  }
  // 收集中间件
  use(fn) {
    this.middlewareList.push(fn)
  }

  listen(...args) {
    const server = http.createServer(this.callback())
    server.listen(...args)
  }

  callback() {
    // 组装中间件
    const fn = this.componse(this.middlewareList)
    return (req, res) => {
      // 生成 ctx
      const ctx = createContext(req, res)
      // 执行中间件
      return this.handle(ctx, fn)
    }
  }

  componse(middlewares) {
    return (ctx) => {
      function dispatch(i) {
        const fn = middlewares[i]
        // 
        try {
          // 传入下一个中间件 dispatch(null, i+1 )
          return Promise.resolve(fn(ctx, dispatch(null, i+1 )))
        } catch (err) {
          return Promise.reject(err)
        }
      }
      return dispatch(0) // 返回第一个中间件函数
    }
  }

  createContext(req, res) {
    const ctx = { req, res }
    ctx.query = req.query
    return ctx
  }

  handle(ctx, fn) {
    fn(ctx)
  }
}