[英]Angular 4 - What is the best way to handle the nested Subscriptions in Iterations
我正在嘗試處理 http 調用的訂閱嵌套在迭代中的情況。
1) 在第一個返回的 observable 中,我會得到一個 URLS 對象
2) 我需要遍歷這些 URL 並對這些 URls 進行 http 調用
3)第三步的情況相同,我將獲取網址並執行與第二步相同的操作
4)最后我從第三步得到的數據我需要推送到最終對象。
let finaldata = [];
this.service1.getstep1Data().subscribe((data1) => {
// data1 = { name : 'abc', urls : ['http://url1.com','http://url2.com',........,'http://urlz.com']};
data1.urls.foreach((url) => {
this.service2.getstep2Data(url).subscribe((data2) => {
// data2 = { name : 'abc', urls : ['http://url1.com','http://url2.com',........,'http://urlz.com']};
data2.urls.foreach((url) => {
this.service3.getfinalData(url).subscribe((data) => {
// data = ["one","two"...."xyz"]
finaldata.push(data[0]);
})
})
})
})
})
現在的問題是處理迭代中的異步調用,它不會相互等待。
我想等待所有異步調用在第二步中完成,然后執行第三步,否則我們沒有第三步的 URLS 來進行休息調用
我知道迭代異步調用不是一個好習慣。
有人可以幫助我進行最佳實踐嗎?
************ 提前致謝 *************
您可以使用forkJoin
執行多個 http 請求並等待所有請求完成。 然后歸結為以正確的方式映射到連接的結果,然后提取您想要的數據。
import { of, Observable, forkJoin } from 'rxjs';
import { switchMap, concatMap, map, reduce } from 'rxjs/operators';
this.service1.getStep1Data()
.pipe(
// we execute multiple getSet2Data requests for each data1 and wait for each to complete
switchMap(data1 => forkJoin(data1.urls.map(url => this.service2.getStep2Data(url)))),
// we spread the data2 responses
switchMap(data2s => of(...data2s)),
// we execute multiple getfinalData requests for each data2 and emit the results in the
// order of the data2 results
concatMap(data2 => forkJoin(data2.urls.map(url => this.service3.getfinalData(url)))),
// we map to the data we want from the finalData result
map(data3perData2 => data3perData2.map(data3 => data3[0])),
// we concatenate the results so that only one array gets emmited
reduce((acc, data) => acc.concat(data))
)
.subscribe(finalData => this.doMyThing(finalData));
或者,您可以使用另一個forkJoin
包裝多個forkJoin
結果,而不是先傳播 data2 響應並稍后減少 Observable 。
this.service1.getStep1Data()
.pipe(
switchMap(data1 => forkJoin(data1.urls.map(url => this.service2.getStep2Data(url)))),
// execute getfinalData for every url from data2 and wait for all results
// do this for every data2 object
switchMap(data2s => forkJoin(data2s.map(data2 => forkJoin(data2.urls.map(url => this.service3.getfinalData(url)))))),
// fullData will be string[][][], so we flatten that to string[] with the first elements
// from data3
map(fullData => [].concat(...fullData).map(data3 => data3[0]))
)
.subscribe(finalData => this.doMyThing(finalData));
最后的映射和減少取決於您希望最終輸出的樣子。
要對服務器 RxJs 操作符(如 mergeMap)進行多次 HTTP 調用,forkJoin 將最好地處理這種情況。
以下示例示例將對您的情況有所幫助。
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { forkJoin } from "rxjs/observable/forkJoin";
@Component({
selector: 'app-root',
templateUrl: 'app/app.component.html'
})
export class AppComponent {
loadedCharacter: {};
constructor(private http: HttpClient) { }
ngOnInit() {
let character = this.http.get('https://swapi.co/api/people/1');
let characterHomeworld = this.http.get('http://swapi.co/api/planets/1');
forkJoin([character, characterHomeworld]).subscribe(results => {
// results[0] is our character
// results[1] is our character homeworld
results[0].homeworld = results[1];
this.loadedCharacter = results[0];
});
}
}
您可以使用 RXJS forkjoin 來實現解決方案。
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular';
constructor(private appservice: AppService){
this.appservice.getService1().subscribe(urls=>{
this.appservice.getService2(urls).subscribe(finalArrayList=>{
this.appservice.getService3(finalArrayList).subscribe();
});
});
}
ngOnInit(){
}
}
創建 Stackblitz https://stackblitz.com/edit/angular-fkh7xr
您可以使用Subject而不是簡單的觀察者。 主題將提供間隔更新,因此將有助於 api 數據的同步使用。
this.api.subjectCreateUser1.subscribe((data1) => {
if (data1) {
this.api.subjectCreateUser2.subscribe((data2) => {
if(data2) {
this.api.subjectCreateUser3.subscribe((data3) => {
if (data3) {
console.log(data3);
}
});
}
});
}
});
和 api 調用如下....
return this.newHttp.post(this._baseApiUrl, this.data1)
.subscribe(success => {
console.log(success);
this.subjectCreateUser1.next(success);
}, error => {
this.subjectCreateUser1.next(error);
});
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.