需要帮助理解链式可观察量

时间:2017-02-15 00:36:03

标签: angular observable

我正在使用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.
  });
}

1 个答案:

答案 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));