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) => {
...
});
