Home > Mobile >  Avoiding nested subscriptions
Avoiding nested subscriptions

Time:01-31

I have a requirement of doing multiple API calls sequentially and using the response of each next call. It looks somewhat like this:

from(Object.keys(someObj))
  .pipe(
    concatMap(key => this.getUsers(key)
  )
  .subscribe(res => ...)

The above code works ok but I needed a delay so some components can process the data between the API calls. So I did:

from(Object.keys(someObj))
  .pipe(
    concatMap(key => of(this.getUsers(key)).pipe(delay(1000))
   )
  .subscribe(res => ...)

This returns a nested observable. How can I subscribe to the inner observable without nesting subscriptions?

I tried to do:

.pipe(
  concatMap(key => of(this.getUsers(key)).pipe(delay(1000)), 
  mergeMap(res => res)
) 

but this, results in an incorrect order of responses.

CodePudding user response:

Thanks to this answer. I tweaked my code to

from(Object.keys(someObj))
  .pipe(
    concatMap(key => merge(this.getUsers(key), EMPTY.pipe(delay(1000))
   )
  .subscribe(res => ...)

This doesn't give me a nested observable and seems to be working well for my requirements. If there is a better approach please do let me know.

CodePudding user response:

I would be suspicious of using delays to give components enough time "to process the data between the api calls". You usually do not know how much time it takes to process the data so you may end up giving too much or too little time.

You should try to see if you can use more of rxjs idiomatic style. What I mean is the following.

Let's assume you have a function processDataBetweenAPICalls(data) which synchronously process the data received from an API call before calling the following API. In this case you could try something like this

from(Object.keys(someObj))
  .pipe(
    concatMap(key => this.getUsers(key)),
    tap(res => processDataBetweenAPICalls(res)
   )
  .subscribe(res => ...)

If instead the processing of the data between 2 API calls is not synchronous but rather is an async process, then I would try to turn this processing into an Observable, in other words I would try to create a function processDataBetweenAPICallsObs(data): Observable<any>. In this case the code could look like

from(Object.keys(someObj))
  .pipe(
    concatMap(key => this.getUsers(key)),
    concatMap(res => processDataBetweenAPICallsObs(res)
   )
  .subscribe(res => ...)

Not knowing in more details your use case, the above suggestions may be not on target.

  • Related