Angular 在执行其他代码之前,确保for循环中的可观察对象都已完成
我有一段代码如下所示:Angular 在执行其他代码之前,确保for循环中的可观察对象都已完成,angular,rxjs,Angular,Rxjs,我有一段代码如下所示: getPersons().subscribe( persons => { for (const person of persons) { getAddress(person.id).subscribe( address => { person.address = address; } )
getPersons().subscribe(
persons => {
for (const person of persons) {
getAddress(person.id).subscribe(
address => {
person.address = address;
}
);
}
doSomethingWithAddresses();
}
);
问题是doSomethingWithAddresses是在所有getAddress可观察对象完成之前执行的。在执行后续代码之前,如何确保它们都已完成?在返回所有观察值之前,应该使用RxJS等待for..of循环完成 以下是您应该对代码所做的更改:
getPersons().subscribe(
persons => {
const observablesList = [];
for (const person of persons) {
const getAddressObservable = getAddress(person.id);
observablesList.push(getAddressObservable)
}
forkJoin(observablesList).subscribe(response => {
// console.log(response) to check that there is a list of returned observables
const result = persons.map((person, index) => {
person['address'] = response[index]['address'];
return person;
})
doSomethingWithAddresses();
})
}
);
或者,您可以尝试此操作以防止链接
subscribe()
试试这个方法
methodOne() {
getPersons().subscribe(
persons => {
for (const person of persons) {
getAddress(person.id).subscribe(
address => {
person.address = address;
}
);
}
}
);
}
async methodTwo() {
await methodOne();
doSomethingWithAddresses();
}
谢谢,这看起来是正确的方法,但在调用doSomethingWithAddresses()之前,我仍然需要将每个地址分配给每个人。用forkJoin可以吗?@Spacejockey实际上是的。当您订阅forkJoin中的Observable时,您会发现它返回了Observable返回值的列表。在伪代码中,您将得到如下内容
[addressObj1、addressObj2、addressObj3等]
。从这里,您可能可以使用Array.map()映射数组中的每个元素,以将地址分配给每个人!让我试着把它添加到我的答案中,以便更清楚地说明它。让我知道如果它有效,我将添加另一个替代解决方案,使它更干净,因为我意识到我在这里嵌套订阅。@wentjun哦,你搞错了,伙计。其实我想学。我在某个地方看到一些人使用mergemap来实现这种场景。但在这里,您创建了一个可观察的列表。我试图理解这个解决方案,并问了这个问题question@SadidKhan很抱歉,我不是故意说得太严厉的。TBH,我认为有几种方法可以解决它,但我的想法是“一块一块”地处理它,并将关注点分开。我认为,如果我们在继续下一组操作之前,等待for..of循环中的可观测值完成,这可能没问题。因此,我决定将它们组合在一起,并在for..of循环完全执行后返回可观测值。。!这是一种“万无一失”的方法,可以确保只有在for循环完成后才会执行doSomethingWithAddresses()
。因为methodOne()
没有跟踪其子订阅或返回任何内容,所以doSomethingWithAddresses()
是否会在不等待它们完成的情况下运行?
let loadedPerson;
getPersons().pipe(
mergeMap(persons => {
return of(persons);
}),
mergeMap(person => {
loadedPerson = person;
return getAddresses(person.id);
}),
map((address) => {
loadedPerson.address = address;
}),
tap(()=>{
doSomethingWithAddresses();
})
).subscribe();
methodOne() {
getPersons().subscribe(
persons => {
for (const person of persons) {
getAddress(person.id).subscribe(
address => {
person.address = address;
}
);
}
}
);
}
async methodTwo() {
await methodOne();
doSomethingWithAddresses();
}