2017-02-15 67 views
0

我正在使用observables,我正在努力瞭解如何在循環中使用它們。需要幫助瞭解鏈式觀察值

在我的項目中,我們加載了一個部件列表,然後循環遍歷每個部件,並且對於循環的每個迭代,我們需要請求一個資源,在應用該資源之前需要等待服務器進行響應。一旦完成,它應該轉移到下一次迭代,最後一次循環的所有迭代都完成後,可觀測值應該完整並且允許應用程序繼續。然而,在繼續前進之前,應用程序並未等待循環的所有迭代完成。

下面是我正在考慮的代碼的示例(請注意這是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

我看到你的代碼的兩個錯誤:

  • subscribe過於頻繁。您應該堅持儘可能長地轉換/鏈接原始可觀察對象,並且最後只需從使用可觀察對象的代碼(即需要使用可觀察對象發出的值的代碼)進行訂閱。
  • 您的所有方法都缺少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}`)); 

的關鍵是使用mergeMap()操作者每次你需要時間的值傳遞給另一個可觀測。

然後,你只認購一次,當你真正需要使用的最終值:

materialsObs.subscribe(material => console.log(material));