订阅完成后,如何从Angular中的promise / observable中设置变量?

时间:2019-03-22 09:42:13

标签: angular promise rxjs observable

我正在给PokeApi打个电话,以获取Pokemon的列表。然后,我需要再次调用以返回每个神奇宝贝的精灵图像。

我能够使用rxjs Observables正确返回Pokemon的列表。当这返回神奇宝贝名称时,我再次调用神奇宝贝详细信息以返回精灵。但是,第二次调用不能及时完成以返回Pokemon Sprites。

public getListOfPokemon(page: number): Observable<Pokemon[]> {
let apiUrl = `${this.apiBaseUrl}/pokemon/?limit=1`;

if (page > 0) {
  let offset = page * 42;

  apiUrl = `${this.apiBaseUrl}/pokemon/?offset=${offset}&limit=42`;
}

return this._httpClient.get(apiUrl).pipe( 
  map((resp: any) => {
    if (resp.results.length == 0) {
      this.lastPageOfResults = resp.next == null;
      this.router.navigate(['/404']);
    }

    this.lastPageOfResults = resp.next == null;

    let pkmnList = _.map(resp.results, (pkmn) => {
      let frontSprite: string;
      let shinySprite: string;

      new Promise(resolve => {
        resolve(this.getPokemonSprites(pkmn.name).subscribe(sprite => {
          return sprite;
        }))
      }).then((value) => {
        console.log(value);
      });

      let singlePkmn = new Pokemon(pkmn.name, frontSprite, shinySprite);

      return singlePkmn;
    });

    return pkmnList;
  })
)

}

当我们返回新的神奇宝贝时,未设置

frontSprite和shinySprite。

编辑 这是getPokemonSprites方法,用于进一步澄清

private getPokemonSprites(name: string): Observable<any> {
let apiUrl = `${this.apiBaseUrl}/pokemon/${name}`;   

return this._httpClient.get(apiUrl).pipe(
  map((pkmnDetail: any) => {
    console.log('hi');
    return pkmnDetail.sprites;
  })
)

}

1 个答案:

答案 0 :(得分:0)

发生这种情况是因为promise.then()执行了异步操作。因此,当您返回new Pokemon()时,可能不会始终设置精灵变量。因此,您需要等待异步操作完成。

因此,对于第二个映射,可以使用map中的switchMap而不是rxjs来订阅内部可观察/链可观察。在switchMap中,您可以将可观察变量数组与combineLatest组合在一起,以得到可观察变量的响应数组。就像下面这样:

getPokemons = () => {

    return this._httpClient.get(apiUrl).pipe( 
      map((resp: any) => {
        if (resp.results.length == 0) {
          this.lastPageOfResults = resp.next == null;
          this.router.navigate(['/404']);
        }

        this.lastPageOfResults = resp.next == null;

        return resp.results;
      }),

      switchMap((pokemonList) => {

        const listOfObservables = [];

        _.map(pokemonList, (pkmn) => {
          let frontSprite: string;
          let shinySprite: string;

          const spriteObservable = this.getPokemonSprites(pkmn.name).pipe(
            map((sprite) => {
               let frontSprite = sprite.front_default;
               let shinySprite = sprite.front_shiny;  
               return new Pokemon(pkmn.name, frontSprite, shinySprite);   
            })
          )

          listOfObservables.push(spriteObservable);

        });

        return combineLatest(listOfObservables);
      })
    )
}

然后,当您调用getPokemons(我将其命名为显示用法)方法时,它将返回一个链式可观察的对象。订阅时,它返回一个Pokemon的数组:

getPokemons.subscribe((pokemonList: Array<Pokemon>) => {
    // do the fancy stuff with pokemonList array
})

希望这会有所帮助。


参考文献:

combine最新:https://www.learnrxjs.io/operators/combination/combinelatest.html

switchMap:https://www.learnrxjs.io/operators/transformation/switchmap.html