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'
source to share
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;
};
source to share
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);
}
source to share