2

node.js に次のような単純なプログラムがあります。

// CODE1
step1();
step2();
var o = step3();
step4(o);
step5();
step6();

このプログラムは、(Web ブラウザではなく) スタンドアロン スクリプトで実行することを意図しており、実行順序が重要なシーケンシャル プログラムです (たとえば、step6 は step5 の後に実行する必要があります)。

問題は、step3() が非同期関数であり、値 'o' が実際には特定のコールバックに渡されるため、次のようにプログラムを変更する必要があることです。

// CODE2
step1();
step2();
step3( function (o) {
  step4(o);
  step5();
  step6();
})

step3 で計算された 'o' 値に依存するため、コールバック関数から step4 を呼び出すことは理にかなっています。しかし、step5 と step6 関数は 'o' に依存しないため、実行順序を保持するためだけにそれらをそのコールバック関数に含める必要があります: step3、次に step4、次に step5、次に step6。

これは私には本当に悪いように聞こえます。これはシーケンシャルなプログラムなので、step3 を同期関数に変換したいと思います。

これを行う方法?私はこのようなものを探しています(例:Qを使用):

// CODE3
step1();
step2();
var deferred = Q.defer();
step3(deferred.resolve);
deferred.blockUntilFulfilled()     // this function does not exist; this is what i am looking for
var o = deferred.inspect().value
step4(o);
step5();
step6();

これを行う方法?

ps: 同期または非同期の使用には長所と短所があり、これは非常に興味深い議論です。ただし、それはこの質問の目的ではありません。この質問では、約束 (または同等のもの) が満たされるまでブロック/待機する方法を尋ねています。同期/ブロックが良いかどうかについての議論を始めないでください。

4

1 に答える 1

3

バニラ JavaScript で非同期操作を同期操作に変えることは不可能です。これを可能にするノード ファイバー (C++ アドオン) や、非同期操作を同期させる (基本的に最初のコード ブロックを 2 番目のコード ブロックに書き直すことによって) JS にコンパイルするさまざまな言語などがありますが、非同期操作が完了するまでブロックすることはできません。

これを確認する 1 つの方法は、JavaScript イベント ループが常に「完了するまで実行される」ことに注意することです。つまり、一連のステートメントがある場合、それらは常に、その間に何もなく、次々に実行されることが保証されます。したがって、外部からの情報が入ってきて、ブロックを停止するようにコードに指示する方法はありません。次のように機能させようとしたとします。

stepA();
stepB();
while (global.operationIsStillGoing) {
  // do nothing
}
stepC();

JavaScript の run-to-completion の性質により、一連のステートメントがまだ完了まで実行されていないためglobal.operationIsStillGoing、ループ中に何かを更新することができないため、これは機能しません。while

もちろん、誰かが言語を変更する C++ アドオンを作成すれば、これを回避できます。しかし、少なくとも一般的に理解されている ECMAScript + イベント ループ アーキテクチャの意味では、これは本当の意味での JavaScript ではなくなりました。

于 2013-07-17T00:29:39.867 に答える