Running the code AFTER a response has been sent by Koa

To optimize response latency, work needs to be done after the response is sent back to the client. However, the only way to make the code run after the response is sent is to use setTimeout

. Is there a better way? Maybe connect the code somewhere after sending the response or run asynchronous code somewhere?

Here is the code.

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'

      

+3


source to share


3 answers


I have the same problem.

koa will finish the response only when all middleware ends (In application.js , respond is response middleware, it terminates the response.)

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);
  }
};

      



But we can solve the problem by calling a function response.end

that is 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;
};

      

0


source


DO NOT call ctx.res.end()

, it is hacked and bypasses the koa / middleware response mechanism, which means you can just use express. Here is the correct solution which I also posted at https://github.com/koajs/koa/issues/474

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'
})

      

No need for ctx.end()


short, do



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

      

NOT

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

      

+6


source


you can run code in async job with setTimeout

like:

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

      

-1


source







All Articles