7

最近、私は新しいプロジェクトに取り組んでおり、このプロジェクトは 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)
4

5 に答える 5

15

明確にするために、コールバックを次のように書きましょう。

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

Koa の世界では、これは a と呼ばれます。これは、thunk引数を 1 つだけ取る非同期関数であることを意味します: プロトタイプ (err, res) を持つコールバック。より良い説明については、https://github.com/visionmedia/node-thunkifyを確認してください。

今、ミドルウェアを書く必要があります

function *loadJson(){
  this.type = 'application/json';
  this.body = yield load;
}
于 2014-02-27T08:04:13.743 に答える
1

これは主に、KOA がジェネレーター ベースであるためです。ミドルウェアの上にある場合、コールバックをサポートしていません。そのため、関数が終了するのを待っていません。最善の解決策は、関数をプロミスに変換することです。promise は KOA でうまく機能します。

于 2015-07-06T12:30:43.770 に答える
0

私は、braintree (通常のコールバック) と koa を使用して非常によく似た問題を抱えていました。あなたのコードに基づいて、私がする必要があった唯一の変更は、load 関数とその呼び出し方法でした。

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

上記の Jerome と Evan による説明は完全に正しく、thunkifyはそれを自動的に実行するための適切なプロセスのように見えます。

于 2015-12-31T06:05:48.417 に答える
0

サンクは良いアイデアでしたが、Promise長期的なアプローチとしては a の方が優れていると思います。多くのライブラリは、古いノード standard の代わりに既に asynccallback(err, data)の promise に移行しており、promise を作成するために async コードをラップするのは非常に簡単です。他の開発者は Promises の経験があり、あなたのコードを自然に理解しますが、ほとんどの開発者は「サンク」とは何かを調べる必要があります。

たとえば、ここでは、まだ約束されていないベースの jsdom を約束にラップしているので、koa ジェネレーターでそれを生成できます。

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

意味的には、promise とジェネレーターは密接に連携して、非同期コードを本当に明確にします。ジェネレーターは何度も再入力して複数の値を生成できますが、プロミスは「後でデータを用意することを約束します」という意味です。これらを組み合わせることで、Koa の最も有用な機能の 1 つを得ることができます。それは、Promise と同期値の両方を生成できることです。

編集:これは、返すPromiseでラップされた元の例です:

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));
  });
}
于 2016-06-15T00:01:19.983 に答える
-1

Koa の組み込み応答処理をバイパスするには、明示的にthis.respond = false; を設定できます。resKoa に応答を処理させるのではなく、生のオブジェクトに書き込みたい場合は、これを使用します。

ヘッダーは、コールバックが呼び出される前に、組み込みの応答処理によって既に書き込まれています。

于 2014-09-22T10:53:59.863 に答える