RxJS - Multiple Requests using forEach and waiting all to finish

左心房为你撑大大i 提交于 2020-06-01 12:37:21

问题


I have this case:

  • First i call a service, and get a list of items. (Array of objects)
  • For each item in this list, i call another service, and they all actually can be fired parallel.
  • I have to wait for all the answers. When i have all the answers, i have a finally logic.

I now have sth like this without using RxJS properly:

this.service.readArray().subscribe((array: Object[]) => {
  if (array.length > 0) {
    array.forEach((item, index) => {

      this.service2.readItem(item.id)
        .subscribe(details => {
          item.details = details;
          // manually finally logic
          if (index === array.length - 1) { // if the last iteration
            ...
          }
        }, (response: HttpErrorResponse) => {
            ...
          // manually finally logic also for error part
          if (index === array.length - 1) { // if the last iteration
          ... 
          }
        });

    });
  } else {
    ... logic for no items in list
  }
}, (error) => {
  ...
});

How can i represent this in a Rxjs (5) statement?


回答1:


You can use forkJoin to wait for all the calls to get finished. Look like you are using rxjs 5 [as you mentioned in your question] so let's change the code like this [see the description in the code comments]:

this.service.readArray()
        .switchMap(array => {
          //lets map the array member to the respective observable
          const obs$ = array.map(item => {

             return this.service2.readItem(item.id)
                        .pipe(
                           catchError(err => {

                             //Do whatever you want to do with this error
                             //make sure to return an observable as per your logic. For this example, I am simply returning the err wrapped in an observable. Having catchError operator will gracefully handle the exception and make sure to emit the value as part of forkJoin.
                             return of(err);

                           })
                         )
          });
          //forkJoin will wait for all the readItem calls get finished.
          return forkJoin(obs$);
        })
        .subscribe((finalArray) => {
          //finalArray will be the array of object [an response of this.service2.readItem(item.id)]
          console.log(finalArray);
          //do whatever you want to do with the array
        });

EDIT - As asked by OP - To get hold of the response of readArray

this.service.readArray()
        .switchMap(array => {
          //lets map the array member to the respective observable
          const obs$ = array.map(item => {

             return this.service2.readItem(item.id)
                        .pipe(
                           catchError(err => {

                             //Do whatever you want to do with this error
                             //make sure to return an observable as per your logic. For this example, I am simply returning the err wrapped in an observable. Having catchError operator will gracefully handle the exception and make sure to emit the value as part of forkJoin.
                             return of(err);

                           })
                         )
          });
          //forkJoin will wait for all the readItem calls get finished.
          return forkJoin(obs$)
                  .pipe(
                    //return the original array along with joined using of
                    mergeMap((joined) => {
                      return of([array, joined]); 
                    })
                  );
        })
        .subscribe((finalArray) => {
          //finalArray will have readArray API response [i.e. array] at 0 index and on 1st index it will have joined array
          console.log(finalArray);
          //do whatever you want to do with the array
        });



回答2:


i have a solution with the zip function as alternative version.

https://stackblitz.com/edit/rxjszipmkx

init() {
   const myService = new MyService();

   myService.getList().subscribe((arr) => {
     let observables = arr.map(value => myService.update(value))
    const allObs$ = zip(...observables);
    allObs$.subscribe((result) => {
      console.log("zip", result);
    }, (error) => { console.log(error) })
  })
}


来源:https://stackoverflow.com/questions/57009546/rxjs-multiple-requests-using-foreach-and-waiting-all-to-finish

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!