koa2小问题
发布于 7 年前 作者 leavesdrift 5565 次浏览 来自 问答
app.use((ctx, next) => {
  const start = new Date;
  console.log('app 1')
  return next().then(() => {
    const ms = new Date - start;
    console.log('app 1 callback')
    console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
  });
});

app.use(async (ctx, next) => {
  const start = new Date;
  console.log('app 2')
  await next();
  const ms = new Date - start;
  console.log('app 2 callback')
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});

app.use(ctx => {
  console.log('app 3')
  ctx.body = "hello KOA";
});
app 1
app 2
app 3
app 2 callback
GET / - 3ms
app 1 callback
GET / - 7ms

刚开始学习 koa2 ,想问一下为什么 ctx.body = ‘xxx’ 会到最后才执行呢,它看起来明明就是一个同步方法,用 promise 理解也就是

return next().then(() => {
  //
  return  next().then(() => {
     // 
	 return next().then(() => {
        ctx.body = 'xxx'
		// 那这一步应该会直接执行才对
	 })
  })

})

13 回复

ctx.body 的确是同步执行的啊,不太理解你的问题 ctx.body = "hello KOA";这一句确实在console.log('app 3')这一句后面执行的,不过在这里他只是一个赋值操作,会等到所有中间件都往回执行完后再返回给客户端,具体可以看看洋葱圈模型。

想知道为什么最后执行,你可以看下koa中间件的源代码,不多,绝对可以让你受益匪浅 自豪地采用 CNodeJS ionic

即使执行了ctx.body = 'hello Koa'这一句.也没有立即返回,需要等待中间件都结束才可以.next的原理应该是类似递归,触发所有中间件之后才会会return Promise.resolve.

@yudawei1230 就是准备看,找个时间研究下

@leemove 我就是不懂这一点,能稍微讲下么?

@feng-fu 为什么会等待所有中间件往回执行完呢?

请求 ==>中间件1 ==> 中间件2 ==> 响应中间件 ==> 2中间件 ==> 1中间件 ==> 响应 洋葱模型 看看源码吧 不要一直问为什么 要自己去看 大家都知道为什么了那大家都可以去开发框架了

@hewentaowx 昨天刚看了一些,源码就是 compose 函数把中间件结合成一个递归表达式,等待最后一个 promise resolve,才会去返回/处理响应

其实很简单,ctx.body 仅仅是一个赋值操作,而把 ctx.body 的数据响应给客户端的实际上是所有中间件执行完毕后调用的 respond 函数,看下面的注释吧

callback() {
    // compose 把中间件聚合成一个函数
    const fn = compose(this.middleware);
    if (!this.listeners('error').length) this.on('error', this.onerror);
    const handleRequest = (req, res) => {
      res.statusCode = 404;
      const ctx = this.createContext(req, res);
      const onerror = err => ctx.onerror(err);
	  // handleResponse 函数实际上调用的是 respond 函数
	  // respond 函数是真正将 ctx.body 赋值到的数据发送给客户端的地方
      const handleResponse = () => respond(ctx);
      onFinished(res, onerror);
	  // 中间件执行完毕后才执行处理响应的函数 handleResponse
      return fn(ctx).then(handleResponse).catch(onerror);
    };

    return handleRequest;
  }

以前写过一个 koa1 和 koa2 的 compose 加载器解析,koa 无论 1 还是 2 的核心都是这个 compose 方法 有兴趣可以看看 跨入Koa2.0,从Compose开始

@hyj1991 对,就是这样的,刚开始不太理解,以为直接赋值操作就会直接返回响应。肯定有兴趣看的,已收藏

回到顶部