[英]Angular 7 nested observables
我有兩個收藏:人和寵物。 每個寵物都有personId。 我的目標是吸引所有人,並讓每個人在單個json中添加他/她的寵物。 到目前為止,我所做的是:
this.personService.getPersions().subscribe(persons => {
const personsWithPets = persons.flatMap(person => this.petService.getPetsByPersonId(person._id)
.subscribe(petsData => {
person.pets = petsData;
return person;
}, (err) => {
console.log(err);
}));
this.persons = personsWithPets; // This is fired before previous subscribe
}, (err) => {
console.log(err);
});
我做錯了什么? 為什么this.persons = personsWithPets;
在訂閱完成之前被解雇?
我為你樹立了榜樣
const { of } = rxjs; const { map, switchMap, toArray, mergeMap } = rxjs.operators; function getPeople() { return of([{ id: 1, name: 'Amanda' }, { id: 2, name: 'Nancy' }]); } function getPetsByPersonId(id) { switch(id) { case 1: return of(['Doggie']); case 2: return of(['Kitten']); } } const getPets = (person) => { return getPetsByPersonId(person.id).pipe( map(pets => ({ ...person, pets })) ) } getPeople().pipe( switchMap(people => people), mergeMap(getPets), toArray() ) .subscribe(peopleWithPets => console.log(peopleWithPets));
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
在內部使用訂閱進行訂閱被認為是不好的做法,並且可能會導致您所描述的問題。 我建議結合使用mergeMap和forkJoin運算符:
this.personService.getPersions().pipe(mergeMap(persons => { const requests = persons.map(person => this.petService.getPetsByPersonId(person._id)); return forkJoin(of(persons), ...requests); }), map(values => { const persons = values[0]; const pets = values.slice(1); // here you need to assign correct pet to correct person }) ).subscribe(personsWithPets => { console.log(personsWithPets); }, err => { console.log(err); });
更新了添加的注釋
另一個: stackblitz
this.service.getPersons().pipe(switchMap((per:any[])=>{
//create an array of observables
const obs=per.map(per=>this.service.getPet(per.id));
//call all of them in forkjoin
return forkJoin(obs).pipe(map(pets=>
//pets is an array, in pets[0] is the response of getPet(1),
//in pets[1] is the response of getPet(2)
pets.map((pet,i)=>{
return {
...per[i], //all the properties of the person
pets:pet //+ in pets an array with the pets of the person
}
})
))
})).subscribe(res=>this.res=res)
可觀察的對象本質上是異步的。 訂閱調用將在另一個線程中運行,而該方法中的其余指令將繼續在主線程中運行。 您需要做的是等到異步操作完成后再運行下一個操作。 您可以通過將這些注解放置在訂閱中來做到這一點,或者更好的方法是使用(err)參數之后的onCompleted參數,如下所示
this.personService.getPersons().subscribe(persons => {
const personsWithPets = persons.flatMap(person =>
this.petService.getPetsByPersonId(person._id)
.subscribe(petsData => {
person.pets = petsData;
return person;
},
(err) => {
console.log(err);
},
() => {
this.persons = personsWithPets;
}))
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.