Koa

119 阅读1分钟

Koa

实例化

const app = new Koa()

this.middleware = [] // 通过实例的 use 方法增加
this.context = Object.create(context)
this.request = Object.create(request)
this.response = Object.create(response)

监听

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

this.callback()

callback () {
  // 聚合函数: 将全部中间件整合成一个函数;
  const fn = compose(this.middleware)

  // 请求回调
  const handleRequest = (req, res) => {
    // 整合 ctx(req res koa的一些针对请求和响应的方法)
    const ctx = this.createContext(req, res)
    return this.handleRequest(ctx, fn)
  }

  return handleRequest
}

handleRequest (ctx, fnMiddleware) {
  const res = ctx.res
  res.statusCode = 404 // 默认返回 404
  const onerror = err => ctx.onerror(err)
  const handleResponse = () => respond(ctx) // res.end(ctx.body)
  // 执行全部的中间件(洋葱圈)
  return fnMiddleware(ctx).then(handleResponse).catch(onerror)
}

洋葱模型

// 后面的中间件先resolve,然后再一个个resolve上来;
function compose (middleware) {
  // 最终收到用户的请求时会执行这个
  return function (context, next/* router中间件会传入这个 */) {
    let index = -1
    // 从第一个开始执行
    return dispatch(0)
    function dispatch (i) {
      index = i
      let fn = middleware[i]
      // 这句router模块会用到
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve() 
      // 包一层 promise
      return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
    }
  }
}

// 看个例子
app.use(async (ctx, next) => {
  console.log(1)
  // 这里是 await 所以会等后面的resolve才继续向下执行
  const res = await next()
  // 等后面的中间件都resolve,才能拿到结果执行
  console.log(res) 
})

koa-router

app.use(router.routes()) // 路由中间件

// 执行 router 的get post等方法,会将回调push进 stack;
// 执行 dispatch 

var dispatch = function dispatch(ctx, next) {

  if (!matched.route) return next()

  layerChain = matchedLayers.reduce(function(memo, layer) {
    memo.push(function(ctx, next) {
      ctx.captures = layer.captures(path, ctx.captures);
      ctx.params = layer.params(path, ctx.captures, ctx.params);
      ctx.routerName = layer.name;
      return next();
    });
    return memo.concat(layer.stack);
  }, []);

  // 执行中间件 这个 next 是router中间件后面那个中间件的执行函数,注意不是一个维度
  return compose(layerChain)(ctx, next);
};