【发布时间】:2019-07-31 19:00:32
【问题描述】:
有没有办法让 Typescript 中的 forEach 循环等待,以便像 http 调用这样的异步代码可以正常完成。
假设我在一个 Angular 组件中有三个数组 a[]、b[] 和 c[]。 共有三个功能,后两个依赖于之前功能的完成。
loadA(){
this.http.get<a[]>(http://getA).subscribe(a=> this.a = a,
()=>loadB());
}
loadB(){
this.a.forEach((res, index)=>{
this.http.get<b[]>('http://getBbyA/res').subscribe(b=> this.b.push(...b),
()=> {
if(index===this.a.length-1){
loadC());
}
}
});
loadC(){
this.b.forEach(res=>{
this.http.get<c[]>('http://getCbyB/res').subscribe(c=> this.c.push(...c));
});
}
现在对于第二种方法,forEach 循环使得在 b[] 数组正确加载从 http 调用获取的数据后调用 loadC() 函数变得不可预测。如何使 loadB() 中的 forEach 循环等待获取所有 http 结果然后调用 loadC() 以避免不可预测性?
更新(使用 RxJs 运算符):
我在我的项目中尝试了以下方法:
loadData(): void {
this.http.post<Requirement[]>(`${this.authService.serverURI}/requirement/get/requirementsByDeal`, this.dealService.deal).pipe(
concatAll(), // flattens the array from the http response into Observables
concatMap(requirement => this.http.post<ProductSet[]>(`${this.authService.serverURI}/productSet/getProductSetsByRequirement`, requirement).pipe( // loads B for each value emitted by source observable. Source observable emits all elements from LoadA-result in this case
concatAll(), // flattens the array from the http response of loadB
concatMap(pSet => this.http.post<Product[]>(`${this.authService.serverURI}/product/get/productsByProductSet`, pSet).pipe( // foreach element of LoadB Response load c
map(product => ({requirement, pSet, product})) // return a object of type { a: LoadAResult, b: LoadBResult, c: LoadCResult}
))
)),
toArray()
).subscribe((results: { requirement: Requirement, productSet: ProductSet, product: Product }[] => {
results.forEach(result => {
this.requirements.push(...result.requirement);
this.productSets.push(...result.productSet);
this.products.push(...result.product);
});
}));
}
但我仍然遇到一些错误 (TS2345)。我哪里出错了?
【问题讨论】:
-
相关问题(但不重复,OP询问
foreach + Observables,这是关于foreach + Promises)stackoverflow.com/questions/18983138/…
标签: angular typescript asynchronous foreach