我正在使用observables,我正在努力了解如何在循环中使用它们。
在我的项目中,我们加载了一个部件列表,然后我们循环遍历每个部分,并且对于循环的每次迭代,我们需要请求一个资源,该资源需要在应用该资源之前等待服务器响应。一旦完成,它应该移动到下一次迭代,最后一旦循环的所有迭代完成,observable应该完成并允许app继续。然而,在继续前进之前,应用程序并没有等待循环的所有迭代完成。
以下是我正在考虑的代码示例(注意这是Angular 2)。
public load(): void {
this.loadParts(this.parts).subscribe(() => {
// This code should wait to run until all of these observables are complete. However for some reason I get here before I get to the code inside the httpService.get observable inside the loadMaterial method below.
}
}
private loadParts(parts: Part[]): Observable<any> {
Observable.create((observer: any) => {
for(part of parts) {
this.applyMaterial(part.material).subscribe();
}
// This observer should be completed when the for loop is done and all materials have been applied.
observer.next();
observer.complete();
});
}
private applyMaterial(material: Material[]): Observable<any> {
this.loadMaterial(material.id).subscribe(() => {
// We need to request the material from the server and wait for the response before applying it here.
}
}
private loadMaterial(materialId: String): Observable<any> {
this.httpService.get(API.LoadMaterialsURL + '/' + materialId).subscribe((response: any) => {
// Update the material service to include the material data returned by the response.
});
}
答案 0 :(得分:0)
我在您的代码中看到两个错误:
subscribe
。你应该坚持尽可能长时间地转换/链接原始的observable,并且最后只从使用observable的代码(即需要使用observable发出的值的代码)订阅。return
语句,这意味着它们中没有一个会返回一个可观察的语句。这是一个粗略的大纲,显示如何在获得所需数据之前链接运算符:
const partIds = [1, 2, 3, 4];
const materialsObs = Observable.from(partIds)
// load the part for a given part id
.mergeMap(partId => this.http.get(`http://api.com/part/${partId}`))
// extract the material id from the loaded part
.map(loadedPart => loadedPart.material.id)
// load the material for a given material id
.mergeMap(materialId => this.http.get(`http://api.com/material/${materialId}`));
关键是每次需要将值传递给另一个observable时都使用mergeMap()
运算符。
然后,当您确实需要使用最终值时,您只订阅ONCE:
materialsObs.subscribe(material => console.log(material));