简体   繁体   中英

angular 5 - loop of observers inside an other observer - efficient way to do it

I have a 'get' call that returns a list of users that contains a user id and a name. After the call succeeded, I need to call another rest for each user to bring his picture.

Currently I am doing this in this way-

component-

users;
userPhotos = {};

constructor(private dashboardService: DashboardService) {
  this.dashboardService.bringUsers().subscribe((data) =>{
    this.users = data;
    this.users.forEach((user) => {
      this.dashboardService.getPicture(user.userID).subscribe((data) => {
        if (data){
          this.userPhotos[user.userID] = window.URL.createObjectURL(data);
        } else {
          this.userPhotos[user.userID] = '';
        }
      });
    });
  });
}

In my html-

<ng-container *ngFor="let user of users">
  <div>
      {{user.displayName}}
  </div>

  <display-picture [image]="userPhotos[user.userID]"></display-picture>
</ng-container>

Where display-picture is a component that just presents the image.

Is there any efficient way using rxjs to do it?

from to iterate each user and mergeScan can be used here to execute the observables. For clarity i break it into two functions. You can also control the number of concurrency with mergeScan

    const getUserPic=users=>from(users).pipe(
        mergeScan((acc, curr:any) =>
            getPicture(curr.userID).pipe(map(photo => {
                acc[curr.userID] = photo
                return acc
            }))
          ,{})
        ) 

bringUsers().pipe(
    tap(users=>this.users=users),
    switchMap(users=> getUserPic(users)),
    last()
).subscribe(console.log)

https://stackblitz.com/edit/rxjs-1bt172

You can use a forkJoin() to merge together all the final emitted values from multiple observables. RxJS 6 supports using an object map of key/value pairs to define which observables, but you'll have to use an array for older versions.

this.dashboardService.bringUsers().pipe(
   switchMap(users => forkJoin(
       users.reduce((acc, user) => (acc[user.userId] = this.dashboardService.getPicture(user.userID), acc), {}
   ))),
).subscribe((users: {[userId: number]: any}) => {
   Object.entries(users).forEach(([userId, data]:[number,any]) => {
      this.userPhotos[user.userID] = data ? window.URL.createObjectURL(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