在KOA中使用带有nodejs的回调

时间:2014-02-27 05:28:23

标签: javascript node.js callback koa

最近我在一个新项目上工作,这个项目在nodejs中使用JavaScript回调。现在我们使用KOA但是当我们尝试使用ES6生成器和回调时会出现问题。

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

现在在KOA我需要调用load并将json响应给客户端,所以我使用下面的代码:

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

但是我收到了这个错误:

_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)

5 个答案:

答案 0 :(得分:15)

为了澄清事情,让我们把你的回调写成

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

在Koa世界中,这被称为thunk,这意味着它是一个只接受一个参数的异步函数:一个带有原型(err,res)的回调。您可以查看https://github.com/visionmedia/node-thunkify以获得更好的解释。

现在你必须用

编写中间件
function *loadJson(){
  this.type = 'application/json';
  this.body = yield load;
}

答案 1 :(得分:1)

这主要是因为KOA是基于生成器的,如果你在中间件的顶端它不支持回调。所以它不等待功能完成。最好的解决方案是将您的功能转换为承诺。承诺与KOA合作很好。

答案 2 :(得分:0)

我使用braintree(常规回调)和koa有一个非常类似的问题。根据您的代码,我需要做的唯一更改是加载函数及其调用方式。

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

以上杰罗姆和埃文的解释是完全正确的,thunkify看起来像是一个自动执行它的合适过程。

答案 3 :(得分:0)

虽然thunks是一个好主意,但在我看来,java -jar start.jar是一个更好的长期方法。许多库已经转向异步的承诺而不是旧的节点标准Promise,并且它们很简单,可以包装任何异步代码来做出承诺。其他开发人员将拥有Promises的经验,并自然地理解您的代码,而大多数人都必须查找“thunk”是什么。

e.g。在这里,我将基于尚未承诺的jsdom包含在承诺中,所以我可以在我的koa发生器中产生它。

callback(err, data)

在语义上,承诺和生成器齐头并进,以真正澄清异步代码。生成器可以多次重新输入并产生多个值,而承诺意味着“我保证稍后会为您提供一些数据”。结合起来,你得到了关于Koa最有用的东西之一:能够同时产生promises和同步值。

编辑:这是你的原始示例,包含一个Promise返回:

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

答案 4 :(得分:-1)

  

要绕过Koa的内置响应处理,您可以明确设置this.respond = false ;.如果要写入原始res对象而不是让Koa为您处理响应,请使用此选项。

在调用回调之前,已经通过内置响应处理编写了标题。