ネスト(入れ子)が深くなる
Angularアプリの開発で、非同期処理を以下のように、連鎖して使うようなケースがあると、ネストが深くなることがあるかと思います。
- AのデータをAPIリクエストで取得
- Bのデータを、Aのデータを使ってAPIリクエストで取得
- 上記の連鎖するような処理を繰り返して、ネストが深くなる。
コードだと以下のような形ですね。
this.aService.getData().subscribe(aData => {
console.log(aData['id']);
this.bService.getData(aData['id']).subscribe(bData => {
console.log(bData['id']);
this.cService.getData(bData['id']).subscribe(cData => {
console.log(cData['id']);
})
})
})
このネストが深くなって、可読性が悪くなるのを解決する方法について、検討していきます。
解決方法
switchMapを使う
switchMapを使えば、以下のようにネストを深くせずに、
連鎖してAPIをリクエストするような処理を記述できます。
this.aService.getData().pipe(
switchMap(dataA => this.bService.getData(dataA['id'])),
switchMap(dataB => this.cService.getData(dataB['id']))
).subscribe(dataC => {
console.log(dataC);
})
forkJoinを使う
各非同期処理が、連鎖的に処理するようなものでなければ、
forkJoinで並列処理して、全ての結果が返ってから、subscribe内の処理をするといったこともができます。
forkJoin({
dataA: this.aService.getData(),
dataB: this.bService.getData(),
dataC: this.cService.getData()
}).subscribe(({ dataA, dataB, dataC}) => {
console.log(dataA, dataB, dataC);
})
async/await + firstValueFrom
async/await + firstValueFromを使って、Promiseに変換することで、
subscribeを使わないようにすることで、ネストが深くなるのを回避できます。
ただ、Observableでなくなるため、Observable特有の複雑なリアクティブ処理をしたいといったケースの場合は不向きです。
async ngOnInit(): Promise<void> {
const aData = await firstValueFrom(this.aService.getData());
const bData = await firstValueFrom(this.bService.getData());
const cData = await firstValueFrom(this.cService.getData());
console.log(aData, bData, cData);
}
まとめ
パターン | おすすめの方法 |
---|---|
順次に非同期処理をしたい | switchMap |
並列に実行し、全て終わったら処理したい | forkJoin |
最小限の処理で簡単に書きたい | async/await + firstValueFrom |