網站搜尋

javascript - 如何「合併」三個或更多的 Observables?


我有這三個來自三個不同服務(3 個 API 調用)的 Observable:

this.gs.getLocationName().subscribe((loc) => this.locationName = loc);
this.gs.getLocationInfo(this.locationName).subscribe((data) => {
    this.lat = data.results.geometry.location.lat;
    this.lon = data.results.geometry.location.lng;
});
this.ws.getWeatherByCoordinates(this.lat, this.lon).subscribe((data) => ...);

如你所見,它取決於先前的可觀測對象,所以我想要一個接一個地執行它們。

我知道如何使用 pipe 和 mergeMap 來「合併」兩個 Observable,但對三個就有問題

我的解決方案是這樣的:

this.gs
      .getLocationName()
      .pipe(
        tap((loc) => {
          this.locationName = loc;
        }),
        mergeMap((loc) => {
          return this.gs.getLocationInfo(this.locationName);
        })
      )
      .pipe(
        tap((data) => {
          this.lat = data.results[0].geometry.location.lat;
          this.lon = data.results[0].geometry.location.lng;
        })
      )
      .subscribe((data) => {
        this.ws.getWeatherByCoordinates(this.lat, this.lon).subscribe((data) => ...);
      });

它有效,雖然我不確定在訂閱中再有訂閱是否是好的作法?

所以我下一個解決方案會是這個:

this.gs
      .getLocationName()
      .pipe(
        tap((loc) => {
          this.locationName = loc;
        }),
        mergeMap((loc) => {
          return this.gs.getLocationInfo(this.locationName);
        })
      )
      .pipe(
        tap((data) => {
          this.lat = data.results[0].geometry.location.lat;
          this.lon = data.results[0].geometry.location.lng;
        }),
        concatMap((data) => {
          return this.ws.getWeatherByCoordinates(this.lat, this.lon);
        })
      )
      .subscribe((data: WeatherModel) => {
        ...
      });

這也可行,但我也不確定我是否做得正確。不確定 concatMap 是否是正確的方法,但至少對我來說有效。

有沒有什麼建議可以幫助我提高程式碼品質?

答案#1

你表現得很好,繼續使用 mergeMap。你可以對多個 Observable 使用 mergeMap

this.gs.getLocationName().pipe(
  tap(loc => this.locationName = loc),
  mergeMap(locationName => this.gs.getLocationInfo(locationName)),
  tap(data => {
    this.lat = data.results.geometry.location.lat;
    this.lon = data.results.geometry.location.lng;
  }),
  mergeMap(data => this.ws.getWeatherByCoordinates(this.lat, this.lon))
).subscribe((data) => {
  ...
});

此外,如果您不打算使用屬性 locationName、lat 和 lon,您可以將上述內容簡化為

this.gs.getLocationName().pipe(
  mergeMap(loc => this.gs.getLocationInfo(locationName)),
  map(data => ({
    lat : data.results.geometry.location.lat,
    lon : data.results.geometry.location.lng;
  })),
  mergeMap(({lat, lon}) => this.ws.getWeatherByCoordinates(lat, lon))
).subscribe((data) => {
  ...
});