Using callbacks with nodejs in KOA

I am working on a new project recently and this project uses javascript callbacks in nodejs. Now we use KOA , but the problem arises when we try to use ES6 generators and callbacks.

//Calback function function load(callback){ result = null; //Do something with xmla4js and ajax callback(result); return result; } 

Now in KOA I need to call load and respond to json client so that I use the following code:

 router= require('koa-router'); app = koa(); app.use(router(app)); app.get('load',loadjson); function *loadJson(){ var that = this; load(function(result){ that.body = result; }); } 

but I get this error:

 _http_outgoing.js:331 throw new Error('Can\'t set headers after they are sent.'); ^ Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11) at Object.module.exports.set (G:\NAP\node_modules\koa\lib\response.js:396:16) at Object.length (G:\NAP\node_modules\koa\lib\response.js:178:10) at Object.body (G:\NAP\node_modules\koa\lib\response.js:149:19) at Object.body (G:\NAP\node_modules\koa\node_modules\delegates\index.js:91:31) at G:\NAP\Server\OlapServer\index.js:40:19 at G:\NAP\Server\OlapServer\OLAPSchemaProvider.js:1599:9 at _LoadCubes.xmlaRequest.success (G:\NAP\Server\OlapServer\OLAPSchemaProvider.js:1107:13) at Object.Xmla._requestSuccess (G:\NAP\node_modules\xmla4js\src\Xmla.js:2113:50) at Object.ajaxOptions.complete (G:\NAP\node_modules\xmla4js\src\Xmla.js:2024:34) 
+7
javascript callback koa
source share
5 answers

To clarify the situation, write your callback as

 //Calback function function load(callback){ setTimeout(function() { var result = JSON.stringify({ 'my': 'json'}); callback(/* error: */ null, result); }, 500); } 

in the Koa world, it's called thunk , which means it's an asynchronous function that takes only one argument: a prototype callback (err, res). you can check https://github.com/visionmedia/node-thunkify for a better explanation.

now you need to write your middleware with

 function *loadJson(){ this.type = 'application/json'; this.body = yield load; } 
+15
source share

this is mainly because KOA is generator-based if you are at the top of the middleware and do not support callbacks. so its not waiting for the completion of the function. the best solution would be to turn your function into a promise. The promise works great with KOA.

+1
source share

I had a very similar problem using braintree (regular callbacks) and koa. Based on your code, the only change I needed to make was the load function and how it was called.

 router = require('koa-router'); app = koa(); app.use(router(app)); app.get('/load',loadjson); function *loadJson(){ this.body = yield load; } // Callback function function load(callback) { // Prepare some data with xmla4js and ajax whatever_inputs = {...}; final_method(whatever_inputs, callback); } 

The explanation of Jerome and Evan above is absolutely true, and thunkify looks like a suitable process to automatically execute it.

0
source share

Although tricks were a good idea, in my opinion, Promise is the best long-term approach. Many libraries are already moving on to promises for async instead of the old callback(err, data) standard node, and they are dead - just wrap around any asynchronous code to make a promise. Other developers will have experience with promises and, of course, will understand your code, while most will have to look for what is "thunk".

eg. here I wrap jsdom in no promise, I promise, so I can concede it in the koa generator.

 const jsdom = require('node-jsdom'); const koa = require('koa'); const app = koa();​ app.use(function *() { this.body = yield new Promise((resolve, reject) => jsdom.env({ url: `http://example.org${this.url}`, done(errors, { document }) { if (errors) reject(errors.message); resolve(`<html>${document.body.outerHTML}</html>`); }, })); });​ app.listen(2112); 

Semantically, promises and generators go hand in hand to really clarify asynchronous code. The generator can be re-entered many times and given several values, while the promise means "I promise that I will have some data for you later." Combined, you get one of the most useful things about Koa: the ability to give both promises and synchronous values.

edit: here is your original example wrapped in Promise to return:

 const router = require('koa-router'); const { load } = require('some-other-lib'); const app = koa(); app.use(router(app)); app.get('load', loadjson); function* loadJson() { this.body = yield new Promise(resolve => { load(result => resolve(result)); }); } 
0
source share

To get around Koa's built-in response processing, you can explicitly set this.respond = false Use this if you want to write the original res object instead of letting Koa handle the response for you.

The header has already been written with built-in response processing before calling the callback.

-one
source share

All Articles