Is it better to subscribe inside a subscription or use rxjs concat with tap

Tags: , , , ,



I reserve data in the backend, then I get all reserved data for that item.
Getting the data must only occur after the reservation so that it will be included.

I have two solutions, but wonder which is the best one and if there is any advantage of using concat with tap in this example:

subscription inside subscription:

...
this.reserveDataItem();
...

reserveDataItem(){
   this.myService.reserveData(this.selectedData).subscribe(res => {
     if (res.status == 'SUCCESS'){
       ...logSuccessMessagesAndOtherStuff
     }
     this.getReservedDataItemsId();
   });
 }


getReservedDataItemsId(){
   this.myService.getReservedDataItemsForRequestId(this.requestId).subscribe(res => {
     if (res.status == 'SUCCESS'){
       ..doStuffWithDataItems
     }
   });
 }

concat with tap:
I used tap because I couldn’t find how to handle different return types in a single subscription
and thus I’m wondering if there is any advantage here..

...
concat(this.reserveDataItem(), this.getReservedDataItemsId())
   .subscribe();
...

reserveDataItem(): Observable<ApiResponseDto<any>>{
  return this.myService.reserveData(this.selectedData).pipe(
    tap(res => {
      if (res.status == 'SUCCESS'){
        ...logSuccessMessagesAndOtherStuff
      }
    })
  )
 }


getReservedDataItemsId():Observable<ApiResponseDto<DataItemDto[]>>{
   return this.myService.getReservedDataItemsForRequestId(this.requestId).pipe(
    tap(res => {
       if (res.status == 'SUCCESS'){
         ..doStuffWithDataItems
       }
     })
  )
 }

Answer

As I understand your question and problem:

You are writing some data on the back-end (first Observable) and after the data is written/saved, you will get a response (complete the first Observable). The response status from the first requirement doesn’t have to be ‘success’, you want to make another request no matter what resp you get. Only after the first Observable completes, you want to make another request to get this data.

Assuming your reserveData method makes one Http request, I would use switchMap:

"For instance, when using switchMap each inner subscription is completed when the source emits, allowing only one active inner subscription." (from the https://www.learnrxjs.io/)

Here is my simplified code, how I would solve the issue:

myObs = new Observable((observer) => {
    observer.next({status: 'SUCCESS'});
    observer.complete();
});

myObs2 = new Observable((observer) => {
    observer.next({status: 'SUCCESS'});
    observer.complete();
});

this.myObs.pipe(
  switchMap((resp) => {
    if (resp.status === 'SUCCESS') ...logSuccessMessagesAndOtherStuff;
    return this.myObs2;
  })
).subscribe(resp => {
  if (resp.status === 'SUCCESS') ...doStuffWithDataItems;
})

Here is my question, which is kind of related to your issue. An Http request/response produces ‘only the last notification (the result from the HTTP request) is returned as seen’ so in my opinion you don’t need to use mergeMap or concatMap (again, assuming your reserveData method basically makes one Http request and returns a response).



Source: stackoverflow