プロミスとジェネレーターを使用すると、非同期コードを作成できます。これらのメカニズムの両方がECMAスクリプト6に導入されている理由がわかりません。いつプロミスを使用するのがベストで、いつジェネレーターを使用するのですか?
これらの2つの手法の間に反対はありません。それらは互いにうまく補完して共存します。 Promiseは、まだ利用できない非同期操作の結果を取得する機能を提供します。 運命のピラミッド 問題を解決します。代わりに:
function ourImportantFunction(callback) {
//... some code 1
task1(function(val1) {
//... some code 2
task2(val1, function(val2) {
//... some code 3
task3(val2, callback);
});
});
}
あなたは書ける:
function ourImportantFunction() {
return Promise.resolve()
.then(function() {
//... some code 1
return task1(val3)
})
.then(function(val2) {
//... some code 2
return task2(val2)
})
.then(function(val2) {
//... some code 3
return task3(val2);
});
}
ourImportantFunction().then(callback);
ただし、promiseを使用しても、非同期方式でコードを作成する必要があります。常にコールバックを関数に渡す必要があります。非同期コードの記述は、同期よりもはるかに困難です。コードが巨大であるという約束でさえ、アルゴリズムを見ることは難しくなります(それは非常に主観的で、誰かがそれについて議論することができます。しかし、プログラマーの大多数にとっては本当だと思います)。したがって、非同期コードを同期方式で記述したいと思います。そこで発電機が私たちを助けに来ています。したがって、上記のコードの代わりに次のように記述できます。
var ourImportantFunction = spawn(function*() {
//... some code 1
var val1 = yield task1();
//... some code 2
var val2 = yield task2(val1);
//... some code 3
var val3 = yield task3(val2);
return val3;
});
ourImportantFunction().then(callback);
最も単純なspawn
実現は次のようになります:
function spawn(generator) {
return function() {
var iter = generator.apply(this, arguments);
return Promise.resolve().then(function onValue(lastValue){
var result = iter.next(lastValue);
var done = result.done;
var value = result.value;
if (done) return value; // generator done, resolve promise
return Promise.resolve(value).then(onValue, iter.throw.bind(iter)); // repeat
});
};
}
ご覧のとおり、value
(非同期関数task{N}
の結果)は約束である必要があります。コールバックでこれを行うことはできません。
あとは、spawn
テクニックを言語自体に実装するだけです。したがって、spawn
をasync
に、yield
をawait
に置き換えて、 ES7 async/await に移行します。
var ourImportantFunction = async function() {
//... some code 1
var val1 = await task1();
//... some code 2
var val2 = await task2(val1);
//... some code 3
var val3 = await task3(val2);
return val3;
}
このビデオ を見て、これと他の今後のテクニックを理解することをお勧めします。男があまりにも速く話している場合は、再生速度を遅くします(右下隅の「設定」、または単に[shift
+ <
]を押します)
最高のもの:コールバック、約束、またはジェネレーターによる約束-これは非常に主観的な質問です。コールバックは、現時点で可能な最速のソリューションです(ネイティブプロミスのパフォーマンスは現在非常に悪いです)。ジェネレーターを使用すると、非同期コードを同期式で作成できます。しかし今のところ、彼らは単純なコールバックよりもずっと遅い。
PromiseとGeneratorは異なるソフトウェアパターン(構築)です。
実際、ジェネレーターは非同期ではありません。
ジェネレータは、一連の値を一度に取得する必要はなく、需要ごとに1つ取得する必要がある場合に役立ちます。ジェネレータは、シーケンスの最後に到達するまで(または無限のシリーズの場合は無限に)、すべての呼び出しで次の値を直ちに(同期的に)返します。
Promiseは、値を「延期」する必要がある場合に役立ちます。値をまだ計算できない(または利用できない)場合があります。値が使用可能な場合-配列またはその他の複雑な値であっても、値全体(値の一部ではない)です。
ウィキペディアの記事で詳細と例を見ることができます。