【问题标题】:Running code AFTER the response has been sent by Koa在 Koa 发送响应后运行代码
【发布时间】:2018-08-02 19:32:27
【问题描述】:

为了优化响应延迟,有必要在响应发送回客户端后执行工作。但是,在发送响应后,我似乎可以让代码运行的唯一方法是使用setTimeout。有没有更好的办法?也许在响应发送后插入代码的地方,或者异步运行代码的地方?

这是一些代码。

koa                  = require 'koa'
router               = require 'koa-router'

app = koa()

# routing
app.use router app

app
  .get '/mypath', (next) ->
    # ...
    console.log 'Sending response'

    yield next

    # send response???

    console.log 'Do some more work that the response shouldn\'t wait for'

【问题讨论】:

标签: javascript optimization generator ecmascript-6 koa


【解决方案1】:

不要调用ctx.res.end(),它很hacky并且绕过了koa的响应/中间件机制,这意味着你最好只使用express。 这是正确的解决方案,我也发布到https://github.com/koajs/koa/issues/474#issuecomment-153394277

app.use(function *(next) {
  // execute next middleware
  yield next
  // note that this promise is NOT yielded so it doesn't delay the response
  // this means this middleware will return before the async operation is finished
  // because of that, you also will not get a 500 if an error occurs, so better log it manually.
  db.queryAsync('INSERT INTO bodies (?)', ['body']).catch(console.log)
})
app.use(function *() {
  this.body = 'Hello World'
})

不需要ctx.end()
所以简而言之,做

function *process(next) {
  yield next;
  processData(this.request.body);
}

不是

function *process(next) {
  yield next;
  yield processData(this.request.body);
}

【讨论】:

    【解决方案2】:

    我也有同样的问题。

    koa只有在所有中间件完成后才会结束响应(application.jsrespond是响应中间件,它结束响应。)

    app.callback = function(){
      var mw = [respond].concat(this.middleware);
      var gen = compose(mw);
      var fn = co.wrap(gen);
      var self = this;
    
      if (!this.listeners('error').length) this.on('error', this.onerror);
    
      return function(req, res){
        res.statusCode = 404;
        var ctx = self.createContext(req, res);
        onFinished(res, ctx.onerror);
        fn.call(ctx).catch(ctx.onerror);
      }
    };
    

    但是,我们可以通过调用response.end节点的api函数来解决问题:

    exports.endResponseEarly = function*(next){
        var res = this.res;
        var body = this.body;
    
        if(res && body){
            body = JSON.stringify(body);
            this.length = Buffer.byteLength(body);
            res.end(body);
        }
    
        yield* next;
    };
    

    【讨论】:

    • 我正在研究同样的问题。我不完全确定我是否遵循您的回答。发送响应后继续的部分是什么?循环中的下一个生成器?
    • 是的,下一个生成器将运行因为yield* next
    • 下一个生成器似乎返回了 404。我猜是因为我的路由处理程序是堆栈中的最后一个。在将结果返回给客户端之后,我正在尝试将响应结果保存到本地缓存。我可以省略 yield *next 并将我的保存代码放在那里——但这似乎不太聪明。
    【解决方案3】:

    你可以使用setTimeout在异步任务中运行代码,就像:

     exports.invoke = function*() {
      setTimeout(function(){
        co(function*(){
          yield doSomeTask();
        });
      },100);
      this.body = 'ok';
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-23
      • 2011-05-17
      • 1970-01-01
      • 1970-01-01
      • 2016-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多