首页 > 解决方案 > 订阅完成后,如何从 Angular 中的 promise/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;
  })
)

}

当我们返回新的 Pokemon 时,没有设置 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;
  })
)

}

标签: angularpromiserxjsobservable

解决方案


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

因此,对于第二个映射,map您可以使用switchMapofrxjs来订阅内部的 observable / 链 observables。并且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(我命名它是为了展示如何使用)方法时,它会返回一个链式 observable。当您订阅时,它会返回一个数组Pokemon

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

希望这可以帮助。


参考:

combineLatest:https ://www.learnrxjs.io/operators/combination/combinelatest.html

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


推荐阅读