5

为了优化响应延迟,有必要在响应被发送回客户端之后执行工作。但是,在发送响应后,我似乎可以让代码运行的唯一方法是使用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'
4

3 回答 3

10

不要调用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);
}
于 2015-11-03T16:08:28.377 回答
0

我也有同样的问题。

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

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但是,我们可以通过调用node的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;
};
于 2015-03-20T09:32:10.653 回答
-3

您可以通过 use 在异步任务中运行代码setTimeout,就像:

 exports.invoke = function*() {
  setTimeout(function(){
    co(function*(){
      yield doSomeTask();
    });
  },100);
  this.body = 'ok';
};
于 2016-12-20T08:15:40.523 回答