我如何 return 一个 Observable 与其他 Observable 的数据一起使用他在其他 Observable 中的 return 值
How can I return an Observable with data of other Observables using his return value in the others
我有一个项目,我想在其中 return Observable
of Hero
对象。
我的英雄们有多个 id 属性来从其他 Observables 获取数据作为 Skill
或 Rarity
。我的 Observables 来自 AngularFire 库。这是我的英雄 class 我现在拥有的东西:
export class Hero extends Serializable {
id?: string;
name?: string;
description?: string;
idRarity?: string;
rarity?: Rarity;
stats: Stats;
idSkill1?: string;
idSkill2?: string;
skill1?: Skill;
skill2?: Skill;
visual?: string;
dateAdded?: Date;
constructor() {
super();
this.stats = {};
this.visual = "assets/images/placeholder.jpg";
}
...
}
// functions from the HeroService
getHeroes(): Observable<Hero[]> {
return this.db.collection<JsonArray>(HeroService.url)
.valueChanges()
.pipe(
map(documents => {
return documents.map(data=> {
return this.getHeroFromData(data);
});
})
);
}
getHero(id: string): Observable<Hero | undefined> {
// Returns hero|undefined observable
return this.getHeroDocument(id).valueChanges()
.pipe(
map(data => {
return data ? this.getHeroFromData(data) : undefined
})
);
}
getHeroFromData(data:JsonArray) {
let hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
this.skillService.getSkill(hero.idSkill1).subscribe(skill => hero.skill1 = skill);
this.skillService.getSkill(hero.idSkill2).subscribe(skill => hero.skill2 = skill);
this.rarityService.getRarity(hero.idRarity).subscribe(rarity => hero.rarity = rarity);
}
return hero;
}
我面临的问题是,当我的英雄 returned 时,我的稀有度和技能属性数据尚未设置。
有没有办法在 returning hero 对象之前等待从其他 Observable 接收到所有值?
RxJs 6.5+
forkJoin 将在这里满足您的要求。
了解 mergeMap 也
// functions from the HeroService
getHero(id: string): Observable<Hero | undefined> {
// Returns hero|undefined observable
return this.getHeroDocument(id)
.valueChanges()
.pipe(
mergeMap((data) => {
return data ? this.getHeroFromData(data) : of(undefined);
})
);
}
getHeroFromData(data: JsonArray): Observable<Hero> {
let hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
forkJoin({
skill1: this.skillService.getSkill(hero.idSkill1),
skill2: this.skillService.getSkil1(hero.idSkill2),
rarity: this.rarityService.getRarity(hero.idRarity),
}).pipe(
map((res) => {
hero.skill1 = res.skill1;
hero.skill2 = res.skill2;
hero.rarity = res.rarity;
return hero;
})
);
}
}
如果你的英雄和技能只加载一次,你应该考虑使用promises而不是observables。如果您不能将其更改为核心,则可以使用 .toPromise()
将可观察对象转换为承诺。然后你可以使用 Promise.all()
.
getHeroFromData(data:JsonArray): Promise<Hero> {
let hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
const promise 1 = this.skillService.getSkill(hero.idSkill1).toPromise().then(skill => hero.skill1 = skill);
const promise2 = this.skillService.getSkill(hero.idSkill2).subscribe(skill => hero.skill2 = skill);
const promise3 = this.rarityService.getRarity(hero.idRarity).subscribe(rarity => hero.rarity = rarity);
return Promise.all([promise1, promise2, promise3]).then(() => hero);
} else {
return Promise.resolve(hero);
}
}
那么在调用该方法时必须使用then
。因为 hero 是以异步方式构建的,所以你必须以异步方式处理 return 。使用 then().
经过几次尝试,我设法使用 zip 运算符
实现了它
这是我最后得到的。
getHeroes(): Observable<Hero[]> {
return this.db.collection<JsonArray>(HeroService.url)
.valueChanges()
.pipe(
mergeMap((docs) => {
return zip(docs.map((doc) => { return this.getHeroFromData(doc) }))
})
);
}
getHero(id: string): Observable<Hero | undefined> {
return this.getHeroDocument(id).valueChanges()
.pipe(
mergeMap(data => { return data ? this.getHeroFromData(data) : of(undefined) })
);
}
private getHeroFromData(data: JsonArray): Observable<Hero> {
const hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
return zip(
this.skillService.getSkill(hero.idSkill1),
this.skillService.getSkill(hero.idSkill2),
this.rarityService.getRarity(hero.idRarity)
).pipe(
map(res => {
console.log(res);
hero.skill1 = res[0];
hero.skill2 = res[1];
hero.rarity = res[2]
return hero;
})
)
}
return of(hero);
}
我有一个项目,我想在其中 return Observable
of Hero
对象。
我的英雄们有多个 id 属性来从其他 Observables 获取数据作为 Skill
或 Rarity
。我的 Observables 来自 AngularFire 库。这是我的英雄 class 我现在拥有的东西:
export class Hero extends Serializable {
id?: string;
name?: string;
description?: string;
idRarity?: string;
rarity?: Rarity;
stats: Stats;
idSkill1?: string;
idSkill2?: string;
skill1?: Skill;
skill2?: Skill;
visual?: string;
dateAdded?: Date;
constructor() {
super();
this.stats = {};
this.visual = "assets/images/placeholder.jpg";
}
...
}
// functions from the HeroService
getHeroes(): Observable<Hero[]> {
return this.db.collection<JsonArray>(HeroService.url)
.valueChanges()
.pipe(
map(documents => {
return documents.map(data=> {
return this.getHeroFromData(data);
});
})
);
}
getHero(id: string): Observable<Hero | undefined> {
// Returns hero|undefined observable
return this.getHeroDocument(id).valueChanges()
.pipe(
map(data => {
return data ? this.getHeroFromData(data) : undefined
})
);
}
getHeroFromData(data:JsonArray) {
let hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
this.skillService.getSkill(hero.idSkill1).subscribe(skill => hero.skill1 = skill);
this.skillService.getSkill(hero.idSkill2).subscribe(skill => hero.skill2 = skill);
this.rarityService.getRarity(hero.idRarity).subscribe(rarity => hero.rarity = rarity);
}
return hero;
}
我面临的问题是,当我的英雄 returned 时,我的稀有度和技能属性数据尚未设置。
有没有办法在 returning hero 对象之前等待从其他 Observable 接收到所有值?
RxJs 6.5+
forkJoin 将在这里满足您的要求。
了解 mergeMap 也
// functions from the HeroService
getHero(id: string): Observable<Hero | undefined> {
// Returns hero|undefined observable
return this.getHeroDocument(id)
.valueChanges()
.pipe(
mergeMap((data) => {
return data ? this.getHeroFromData(data) : of(undefined);
})
);
}
getHeroFromData(data: JsonArray): Observable<Hero> {
let hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
forkJoin({
skill1: this.skillService.getSkill(hero.idSkill1),
skill2: this.skillService.getSkil1(hero.idSkill2),
rarity: this.rarityService.getRarity(hero.idRarity),
}).pipe(
map((res) => {
hero.skill1 = res.skill1;
hero.skill2 = res.skill2;
hero.rarity = res.rarity;
return hero;
})
);
}
}
如果你的英雄和技能只加载一次,你应该考虑使用promises而不是observables。如果您不能将其更改为核心,则可以使用 .toPromise()
将可观察对象转换为承诺。然后你可以使用 Promise.all()
.
getHeroFromData(data:JsonArray): Promise<Hero> {
let hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
const promise 1 = this.skillService.getSkill(hero.idSkill1).toPromise().then(skill => hero.skill1 = skill);
const promise2 = this.skillService.getSkill(hero.idSkill2).subscribe(skill => hero.skill2 = skill);
const promise3 = this.rarityService.getRarity(hero.idRarity).subscribe(rarity => hero.rarity = rarity);
return Promise.all([promise1, promise2, promise3]).then(() => hero);
} else {
return Promise.resolve(hero);
}
}
那么在调用该方法时必须使用then
。因为 hero 是以异步方式构建的,所以你必须以异步方式处理 return 。使用 then().
经过几次尝试,我设法使用 zip 运算符
实现了它这是我最后得到的。
getHeroes(): Observable<Hero[]> {
return this.db.collection<JsonArray>(HeroService.url)
.valueChanges()
.pipe(
mergeMap((docs) => {
return zip(docs.map((doc) => { return this.getHeroFromData(doc) }))
})
);
}
getHero(id: string): Observable<Hero | undefined> {
return this.getHeroDocument(id).valueChanges()
.pipe(
mergeMap(data => { return data ? this.getHeroFromData(data) : of(undefined) })
);
}
private getHeroFromData(data: JsonArray): Observable<Hero> {
const hero = new Hero().fromJSON(data);
if (hero.idSkill1 && hero.idSkill2 && hero.idRarity) {
return zip(
this.skillService.getSkill(hero.idSkill1),
this.skillService.getSkill(hero.idSkill2),
this.rarityService.getRarity(hero.idRarity)
).pipe(
map(res => {
console.log(res);
hero.skill1 = res[0];
hero.skill2 = res[1];
hero.rarity = res[2]
return hero;
})
)
}
return of(hero);
}