Observableを返すangular 2共通HTTPを使用していますが、ネストされたObservable呼び出しを使用すると、コードがメッシュを好むという問題に直面します。
this.serviceA.get().subscribe((res1: any) => {
this.serviceB.get(res1).subscribe((res2: any) => {
this.serviceC.get(res2).subscribe((res3: any) => {
})
})
})
今、私はそれを避けるためにasync/awaitを使いたいが、async/awaitはPromiseでのみ動作する。 ObservableはPromiseに変換できることを知っていますが、私が知っているように、それは良い習慣ではありません。だから私はここで何をすべきですか?
ところで、誰かが私にasync/awaitでこれを解決するためのサンプルコードを与えることができれば素晴らしいでしょう:D
コード例に関して、Observableをチェーンする(前の出力の後に別のトリガーをトリガーする)場合は、この目的でflatMap
(またはswitchMap
)を使用します。
this.serviceA.get()
.flatMap((res1: any) => this.serviceB.get())
.flatMap((res2: any) => this.serviceC.get())
.subscribe( (res3: any) => {
....
});
ObservableとPromisesがそもそも防止に役立つはずだったコールバックの地獄を避けるために、これは物事を明確にし、あなたを助けるので、これはネストに比べてより良い習慣です。
また、switchMap
の代わりにflatMap
を使用することを検討してください。最初のリクエストが新しい値を発行した場合、基本的に他のリクエストを「キャンセル」できます。たとえば、残りをトリガーする最初のObservableがボタンのクリックイベントである場合に使用すると便利です。
さまざまなリクエストを順番に待つ必要がない場合は、forkJoin
またはZip
を使用してそれらを一度に開始できます。 @ Dan Macak answer's 詳細およびその他の洞察。
ObservablesとAngularに関しては、コンポーネントコードでObservableにサブスクライブする代わりに、Angularテンプレートで| async
パイプを完全に使用して、このObservableによって発行された値を取得できます。
observableを直接使用していると感じていない場合は、Observableで.toPromise()
を使用してから、async/await命令を使用できます。
Observableが結果を1つだけ返すことになっている場合(基本的なAPI呼び出しの場合)、ObservableはPromiseとまったく同等と見なすことができます。
ただし、Observableがすでに提供しているすべてのものを考慮すると、それを行う必要があるかどうかはわかりません(読者へ:啓発的な反例を歓迎します!)トレーニング演習として、できる限りObservablesを使用することをお勧めします。
それに関するいくつかの興味深いブログ記事(および他にもたくさんあります):
https://medium.com/@benlesh/rxjs-observable-interop-with-promises-and-async-await-bebb05306875
ToPromise関数は、実際には「演算子」ではなく、ObservableにサブスクライブしてPromiseにラップするRxJS固有の手段であるため、実際には少し注意が必要です。 Observableが完了すると、PromiseはObservableの最後に発行された値に解決されます。つまり、Observableが値「hi」を発行し、10秒待ってから完了すると、返されたプロミスは10秒待ってから「hi」を解決します。 Observableが完了しない場合、Promiseは解決しません。
注:toPromise()の使用は、async-awaitなど、Promiseを期待するAPIを扱っている場合を除き、アンチパターンです
(エンファシス鉱山)
ところで、誰かが私にasync/awaitでこれを解決するためのサンプルコードを与えることができれば素晴らしいでしょう:D
本当にしたい場合の例(おそらくいくつかの間違いがあり、今すぐチェックできないため、お気軽に修正してください)
// Warning, probable anti-pattern below
async myFunction() {
const res1 = await this.serviceA.get().toPromise();
const res2 = await this.serviceB.get().toPromise();
const res3 = await this.serviceC.get().toPromise();
// other stuff with results
}
すべての要求を同時に開始できる場合は、await Promise.all()
の方が効率的です。これは、呼び出しが相互の結果に依存しないためです。 (forkJoin
Observablesと同様)
async myFunction() {
const promise1 = this.serviceA.get().toPromise();
const promise2 = this.serviceB.get().toPromise();
const promise3 = this.serviceC.get().toPromise();
let res = await Promise.all([promise1, promise2, promise3]);
// here you can promises results,
// res[0], res[1], res[2] respectively.
}
@ Pac0はすでにさまざまなソリューションについて詳しく説明しているので、少しだけ異なる角度を追加します。
個人的にはPromiseとObservablesを混在させない-Observablesで非同期待機を使用しているときに得られるものです。
両方を使用することは時々有効ですが、特にwith Angular RxJSを可能な限り使用することを検討すべきだと思います。その理由は:
async
パイプがあり、サーバーからのデータストリームを中断することなく、アプリケーションのデータフロー全体を作成し、フィルタリング、結合、および任意の変更を行うことができます単一の必要なしにtheningまたはサブスクライブの場合。このように、データをアンラップしたり、いくつかの補助変数に割り当てる必要はありません。データはサービスからObservablesを介してテンプレートに直接流れるだけで、とても美しいです。ただし、Promise can be shineの場合もあります。たとえば、rxjsTypeScriptタイプに欠けているのは、singleの概念です。他の人が使用するAPIを作成している場合、Observableを返すだけでは十分ではありません。1つの値を受け取りますか、多くの値を受け取りますか、それとも完全に完了しますか。それを説明するコメントを書く必要があります。一方、Promiseはこの場合、より明確な契約を結んでいます。常に1つの値で解決されるか、エラーで拒否されます(もちろん永遠にハングアップしない限り)。
通常、プロジェクトにPromisesまたはObservablesのみを含める必要はありません。何かが完了したことを値で表現したい場合(ユーザーの削除、ユーザーの更新)、それを統合せずに対応したい場合いくつかのストリーム、Promiseはそうするより自然な方法です。また、async/await
を使用すると、コードをシーケンシャルに記述できるため、コードを大幅に簡素化できます。したがって、着信値の高度な管理が必要でない限り、Promiseをそのまま使用できます。
したがって、私の推奨事項は、RxJSとAngulaの両方の力を取り入れる rです。あなたの例に戻ると、次のようにコードを書くことができます(@Vayrexへのアイデアの功績):
this.result$ = Observable.forkJoin(
this.serviceA.get(),
this.serviceB.get(),
this.serviceC.get()
);
this.result$.subscribe(([resA, resB, resC]) => ...)
このコードは3つのリクエストを実行し、それらのリクエストObservablesがすべて完了すると、forkJoin
へのサブスクリプションコールバックにより配列で結果が取得され、前述のように手動でサブスクライブできます(例のように) )またはテンプレートでresult$
およびasync
パイプを使用して宣言的にこれを行います。
Observable.Zip
を使用すると、ここで同じ結果が得られます。forkJoin
とZip
の違いは、前者は内部Observableの最後の値のみを出力し、後者は内部Observableの最初の値を組み合わせ、次に、2番目の値など.
編集:以前のHTTPリクエストの結果が必要なので、@ Pac0の回答でflatMap
アプローチを使用します。