0

getEnrolledPlayers should fetch an array of 'player' objects from the database and then pass it to the matchMaking function. However, it doesn't get passed correctly.

I tried adding observables, playing around with subscriptions

initializeEvent(eventId: string) {
  const enrolledPlayers: PlayerStat[] = [];
  this.getEnrolledPlayers(eventId)
    .subscribe((playerIds: string[]) => {
      for (const playerId of playerIds) {
        this.dataService.fetchSinglePlayer(playerId)
          .subscribe((playerStat: PlayerStat) => enrolledPlayers.push(playerStat));
      }
      this.matchMaking(enrolledPlayers);
    });
}

When I call these series of asynchronous functions, enrolledPlayers[] is calculated correctly (array of 7 elements), but it doesn't get called to the matchMaking() function correctly. I assume it's because of asynchronous runtime.

2
  • ` this.matchMaking(enrolledPlayers);` should be in your inner subscribe() function Commented Jul 16, 2019 at 15:50
  • @HaifengZhang you mergeMap would be better Commented Jul 16, 2019 at 15:54

2 Answers 2

3

Yes. It's definitely an issue caused because of the time difference in which the inner subscription resolves a value.

I'd suggest using a forkJoin and waiting on getting all the values resolved before calling matchMaking.

Give this a try:

initializeEvent(eventId: string) {
  const enrolledPlayers: PlayerStat[] = [];
  this.getEnrolledPlayers(eventId)
    .subscribe((playerIds: string[]) => {
      const playerInfos$ = playerIds.map(playerId => this.dataService.fetchSinglePlayer(playerId));
      forkJoin(...playerInfos$)
        .subscribe(enrolledPlayers: PlayerStat[] => this.matchMaking(enrolledPlayers));
    });
}

Or with one subscribe

initializeEvent(eventId: string) {
  const enrolledPlayers: PlayerStat[] = [];
  this.getEnrolledPlayers(eventId)
    .take(1)
    .switchMap((playerIds: string[]) => {
      const playerInfos$ = playerIds.map(playerId => this.dataService.fetchSinglePlayer(playerId).take(1));
      return forkJoin(...playerInfos$);
    })
   .tap(this.matchMaking)
    .subscribe();
}
Sign up to request clarification or add additional context in comments.

2 Comments

single subscribe is the correct answer here. nested subscribes is an anti pattern. but you should answer this in rxjs 6+ syntax
Totally agree @bryan60.
2

this is a nested subscribe anti pattern... you never nest subscribes, this is how it should look using higher order operators:

initializeEvent(eventId: string) {
  this.getEnrolledPlayers(eventId)
    .pipe(
      switchMap(playerIds => 
         forkJoin(playerIds.map(playerId => this.dataService.fetchSinglePlayer(playerId)))
      )
    ).subscribe((enrolledPlayers) => 
      this.matchMaking(enrolledPlayers)
    );
}

use switchMap to switch into a new observable and then forkJoin to run many observables in parrallel

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.