質問

最近、新しいプロジェクトに取り組んでいますが、このプロジェクトでは、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)
役に立ちましたか?

解決

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

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

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

ここでミドルウェアを作成する必要があります

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

他のヒント

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

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

上記のジェロームとエヴァンの説明は完全に正しいです。 サンクファイ それを自動的に行うのに適したプロセスのように見えます。

「サンク」は良いアイデアですが、私の意見では、 Promise 長期的なアプローチとしては優れています。多くのライブラリはすでに、古いノード標準ではなく非同期の Promise に移行しています。 callback(err, data), そして、非同期コードをラップして約束するのは非常に簡単です。他の開発者は Promise の経験があり、自然にコードを理解するでしょうが、ほとんどの開発者は「サンク」とは何かを調べる必要があります。

例えばここでは、まだ Promise ベースではない jsdom を Promise でラップしているので、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 とジェネレーターは連携して非同期コードを明確にします。ジェネレーターは何度も再入力して複数の値を生成できますが、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));
  });
}

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top