0

I have a method in a service that iterates synchronous with a for loop. In this for loop I have an async call and i want only to continue the loop when the async call is done. Do I need some kind of eventemitter that emits to the async called value? Couse I now for a fact the async call will open up i different thread so the for loop iterates, through without even waiting if the call is done. Here my method from the service:

private mapHeroTypeToDisplayHeroType(heroList: TroopsHeroesAndSpellType[]): Observable<HeroDisplay[]> {
    const heroesWithImgArray: HeroDisplay[] = [];
    for (const hero of heroList) {
        Object.keys(Heroes).filter(HeroesKey => {
            if (hero.name === Heroes[HeroesKey]) {
                Object.keys(HeroesImg).filter(HeroesImgKey => {
                    if (<Heroes>HeroesKey as string === <HeroesImg>HeroesImgKey as string) {
                        this.storage.ref(HeroesImg[HeroesImgKey]).getDownloadURL().subscribe((data: HeroesImg) => {
                            let heroObj = {
                                name: hero.name,
                                level: hero.level,
                                maxLevel: hero.maxLevel,
                                village: hero.village,
                                heroImg: data
                            };
                            heroesWithImgArray.push(heroObj);
                        });
                    }
                });
            }
        });
    }
    return Observable.of(heroesWithImgArray);
}
CozyAzure
  • 8,280
  • 7
  • 34
  • 52
MarcoLe
  • 2,309
  • 6
  • 36
  • 74
  • Stick to promises and async/await. You don't have real reason to use observables here, do you? – Estus Flask Apr 04 '18 at 17:00
  • getDownloadUrl returns a observable so i dont know if i need to return the array in a observable but the getDownloadUrl definitely returns a observable obj. – MarcoLe Apr 04 '18 at 17:03
  • You can't return anything in observable `subscribe` because it's async and you will end up with this problem, http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call . The question lacks http://stackoverflow.com/help/mcve, it's unclear what getDownloadUrl is. Is it completed observable? Then you can convert with toPromise() and stick to promises any way. – Estus Flask Apr 04 '18 at 17:05
  • but when i execute `mapHeroTypeToDisplayHeroType(hero).subscribe.....` i get the data fully but in a wrong order. so i suspect its due to the for loop iterates through without waiting. Do you have an approach how to solve this? btw. getdownloadUrl is a method from angularFirebase package it returns a url from a img – MarcoLe Apr 04 '18 at 17:52
  • Yes, with async/await, as it was said above. async/await isn't compatible with .filter, so it should be replaced with for..of (.filter is misused, it doesn't filter anything). It could also be done with observables alone, but `for` and `filter` should be avoided. I'm unable to provide the code for the answer because original code is hard to follow. Hope this helps. – Estus Flask Apr 04 '18 at 17:59

1 Answers1

0

Solution was - Observables forkJoin - and it looks like this:

  private mapHeroTypeToDisplayHeroType(heroList: TroopsHeroesAndSpellType[]): Observable<HeroDisplay[]> {
const observables: Observable<HeroDisplay>[] = [];
let heroObj: HeroDisplay;
for (const hero of heroList) {
  for (const heroesKey in Heroes) {
    if (hero.name === Heroes[heroesKey]) {
      for (const heroesImgKey in HeroesImg) {
        if (<Heroes>heroesKey as string === <HeroesImg>heroesImgKey) {
         const singleHeroImgObservable =
           this.storage.ref(HeroesImg[heroesImgKey]).getDownloadURL().map((data: HeroesImg) => {
            return  heroObj = {
              name: hero.name, level: hero.level, maxLevel: hero.maxLevel, village: hero.village, heroImg: data
            };
          });
          observables.push(singleHeroImgObservable);
        }
      }
    }
  }
}
return Observable.forkJoin(observables);

}

MarcoLe
  • 2,309
  • 6
  • 36
  • 74