angular - 订阅完成后,如何从 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;
})
)
}
解决方案
发生这种情况是因为promise.then()
执行了异步操作。因此,当您返回时new Pokemon()
,可能并不总是设置精灵变量。所以你需要等待异步操作完成。
因此,对于第二个映射,map
您可以使用switchMap
ofrxjs
来订阅内部的 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
推荐阅读
- php - php如何进行部分搜索/输入和下拉菜单搜索?
- javascript - Vue getter/setter 行为在 * 和 / 为 100 时显示出意外的副作用
- r - 优化 data.table 中的矢量扫描
- mongodb - 如何彻底销毁 docker-compose 创建的 Mongo 数据库?
- linux - 访问 Linux 服务配置文件中的环境变量
- python - 如何禁用打印“正在加载配置...完成。” 在相扑/特雷西
- python - Alembic:如何在迁移脚本中添加新的枚举类型而不使用`alembic.op.execute`
- julia - 如何解决在 Julia 中执行发布请求的错误 400
- html - 我在 xhtml 严格 1.0 验证时遇到问题
- c++ - 指针在链表深拷贝构造函数中永远不会达到 null