简体   繁体   中英

How to "combine" 3 or more Observables?

I have these 3 Observables from 3 different Services (3 API calls):

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

As you can see it depends on the previous Observable, so I want to run them one by one.

I know how to "combine" 2 Observable with a pipe and mergeMap for example but have a problem with 3

My solution is like this:

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

It works though I am not sure if it is good practice to have a Subscription in a Subscription?

So my next solution would be this:

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

This also works but I am also not sure if I did it correctly. Not sure if concatMap is the way to goo but it works for me at least.

Any tips how I can improve my code quality?

You were doing well, continue with mergeMap . You can mergeMap more than one Observable

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

Furthermore, if you will not be using the properties locationName , lat and lon , you can reduce the above to

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM