19

Node.js にジェネレーターが追加されました。

私の理解では、ジェネレーターを使用して、はるかに直線的に見えるコードを記述し、コールバックの地獄とドゥーム スタイルのコーディングのピラミッドを回避できます。

したがって、ここまでの私の理解では、ジェネレーター内では、コードは「yield」ステートメントに到達するまで実行されます。ジェネレーター関数の実行は、この時点で中断されます。ステートメントはyield、関数である可能性がある戻り値を指定します。通常、これはブロッキング I/O 関数であり、通常は非同期で実行する必要があります。

yield の return 関数は、ジェネレーターと呼ばれるものに返されます。

私の質問は、この時点で何が起こるかです。yield が返したブロッキング I/O 関数を正確に実行するのは何ですか?

線形に見えるジェネレーター/yield コードを記述するには、ジェネレーターを呼び出す特定の種類の関数、ジェネレーターをループして、yield によって返される各非同期関数を実行する関数が必要であるというのは正しいですか?非同期関数の結果をジェネレーターに戻しますか?

yield によって返された非同期関数がどのように実行されるかは、まだ正確にはわかりません。ジェネレーターを呼び出す関数で実行する場合、非同期で実行されますか? そうしないとブロック動作が発生するため、私はそう推測しています。

私の質問を要約すると:

  1. ジェネレーターを使用して「線形」非同期コードを記述するには、ジェネレーターを反復処理し、生成された関数をコールバックとして実行し、コールバックの結果をジェネレーターに返す呼び出し関数が必要ですか?
  2. 質問 1 の答えが「はい」の場合、生成された関数は正確にどのように非同期で実行されますか?

プロセス全体がどのように機能するかについて、より良い概要/要約を提供できる人はいますか?

4

3 に答える 3

13

ジェネレーターを使用して非同期コードを記述する場合、次の 2 種類の関数を扱います。

  • で宣言された通常のfunction関数。これらの関数は生成できません。それらは完了するまで実行されるため、同期スタイルで非同期コードを記述することはできません。コールバックを介してのみ非同期完了を処理できます (node-fibersライブラリやコード変換などの特別な機能を呼び出さない限り)。
  • で宣言されたジェネレーターfunction*関数。これらの関数生成できます。それらは生成される可能性があるため、それらの内部に同期スタイルで非同期コードを記述できます。ただし、ジェネレーターを作成し、コールバックを処理し、コールバックが発生するたびに呼び出しでジェネレーターを再開するコンパニオン関数が必要です。next

コンパニオン関数を実装するライブラリがいくつかあります。これらのライブラリのほとんどでは、コンパニオン関数は一度に 1 つfunction*を処理するため、コード内のすべてfunction*にラッパーを配置する必要があります。galaxy ライブラリ (私が作成したもの) は、中間ラッパーなしfunction*で other の呼び出しを処理できるため、少し特殊です。function*コンパニオン関数は、ジェネレーターのスタックを処理する必要があるため、少し注意が必要です。

ユーザー関数とコンパニオン関数のyield/next間のダンスが少ないため、実行フローを理解するのが難しい場合があります。function*フローを理解する 1 つの方法は、選択したライブラリを使用して例をconsole.log記述し、コードとライブラリの両方にステートメントを追加して実行することです。

于 2013-09-19T21:00:41.403 に答える
4

ジェネレーターを呼び出す関数で【ブロッキングio関数】を実行する場合、非同期で実行されますか?そうしないとブロック動作が発生するため、私はそう推測しています。

ジェネレーターが非同期タスク処理を行うとは思いません。ジェネレーターでは、同時に実行されるのは 1 つのことだけです。つまり、1 つの関数が実行を停止して、別の関数に制御を渡すことができるということです。例えば、

function iofunc1() {
  console.log('iofunc1');
}

function iofunc2() {
  console.log('iofunc2');
}

function* do_stuff() {
  yield iofunc1;
  yield iofunc2;
  console.log('goodbye');
}


var gen = do_stuff();
(gen.next().value)(); 
(gen.next().value)(); //This line won't begin execution until the function call on the previous line returns
gen.next(); //continue executing do_stuff

nodejs ジェネレーターに関するいくつかの記事を読んだ場合:

  1. http://jlong​​ster.com/2012/10/05/javascript-yield.html
  2. http://jlong​​ster.com/A-Study-on-Solving-Callbacks-with-JavaScript-Generators
  3. http://jlong​​ster.com/A-Closer-Look-at-Generators-Without-Promises

...それらはすべて、追加の関数/ライブラリを使用して非同期実行を追加します。

于 2013-07-07T23:18:28.853 に答える
2

1: ジェネレーターを使用して「線形」非同期コードを作成するには、ジェネレーターを反復処理し、生成された関数をコールバックとして実行し、コールバックの結果をジェネレーターに返す呼び出し関数が必要ですか?

はい。それを「ランチャー」と呼びましょう。

2: 質問 1 の答えが「はい」の場合、生成された関数は正確にどのように非同期で実行されますか?

ジェネレーター内で、関数とそのパラメーターを含む配列を生成します。制御呼び出し元 (ランチャー) では、fn.apply(..,callback) を使用して非同期を呼び出し、"generator.next(data);" への呼び出しを行います。(再開) コールバック内。

async 関数は非同期で実行されますが、ジェネレーターは、コールバックが呼び出されるまで (そして "generator.next(data)" が実行されるまで)、yield ポイントで "一時停止" されます。

完全に動作するライブラリとサンプル: https://github.com/luciotato/waitfor-es6

于 2013-11-24T01:14:55.200 に答える