Angular map等待Observable完成



我试图在我的Observable函数中发送httpclient,它将在没有httpclient完成的情况下运行。

下面是一个用于复制

的演示代码
test() {
this.test2()
.pipe(
mergeMap((result) => {
console.log(result[0]);
return of([]);
})
)
.subscribe();
}
test1(): Observable<any> {
return of(this.getStudents());
}
test2(): Observable<any> {
return this.test1().pipe(
mergeMap((result) => {
if (result) {
result.map((rr) => {
if (rr.age == 1) {
this.client
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.subscribe((res) => {
console.log(res);
rr.age = rr.age * 10000;
});
} else {
rr.age = rr.age * 10;
}
return rr;
});
}
return of(result);
})
);
}
getStudents(): Student[] {
return [{ age: 1 }, { age: 2 }, { age: 3 }];
}

这是Student

export class Student {
age: number;
}

对于预期的结果,console.log(res);应该在console.log(result[0]);之前返回。

我已经尝试了很多方法,如.toPromiseasync await,但未能使其工作。

你可以在下面分叉一个测试版本:

https://stackblitz.com/edit/save-file-to-drive-7dawzd?file=src/app/app.component.ts

根据您的预期结果,您需要在打印Student[0]之前先完成api调用。

你的代码中的问题:

  • 你正在订阅一个你没有等待的api调用完成,因此console.log(result[0])console.log(res);之前先打印,因为api调用还没有完成。

我使用了几个RXJS操作符来得到你想要的。

  • mergeMap平铺内部可观察对象
  • of将student数组转换为可观察对象
  • map将当前数组转换为具有相应新年龄的新数组
  • forkJoin-我们将多个请求包装到一个可观察对象中,并且只有在收到所有请求的响应时才会返回。

这当然只是一种方法,可能还有其他更好的方法。

test() {
this.test2()
.pipe(
mergeMap((result) => {
console.log(result);
if (result && result.length > 0) {
console.log(result[0]);
}
return of([]);
})
)
.subscribe();
}
test1(): Observable < Student[] > {
// return of(null);
return of(this.getStudents());
}
test2(): Observable < Student[] > {
return this.test1().pipe(
mergeMap((result) => {
if (!result) {
return of(result);
}
return forkJoin(
result.map((rr) =>
rr.age === 1 ?
this.client
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.pipe(
map((res) => {
console.log(res);
return (rr.age = rr.age * 10000);
})
) :
of ((rr.age = rr.age * 10))
)
).pipe(
map((paths) => {
return result.map((e, index) => ({
age: paths[index],
}));
})
);
})
);
}
getStudents(): Student[] {
return [{
age: 1
}, {
age: 2
}, {
age: 3
}];
}

我修改了您创建的模拟解决方案的stackblitz。

RxJS方式:

虽然点击api端点而忽略它的结果很奇怪,但您可以确保使用任何RxJS高阶操作符(如mergeMap, switchMap, concatMap等)等待该结果。

由于要对整个数组执行此操作,因此选择forkJoin是很自然的。forkJoin将订阅所有的可观察对象,并在完成后为每个发出最后值的数组。.

test() {
// mergeMap here is silly, it doesn't merge or map anything in a 
// meaningful way. I've removed it.
this.test2().subscribe(
students => console.log(students[0])
);
}
test1(): Observable<Student[]> {
return of(this.getStudents());
}
test2(): Observable<Student[]> {
return this.test1().pipe(
map(students => students?.map(student => {
if(student.age == 1){
return this.client.get(
'https://api.coindesk.com/v1/bpi/currentprice.json'
).pipe(
tap(currentPrice => console.log(currentPrice)),
mapTo({...student, age: student.age * 1000})
)
}else{
return of({...student, age: student.age * 10})
}
})),
mergeMap(studentCalls => forkJoin(studentCalls))
);
}
getStudents(): Student[] {
return [{ age: 1 }, { age: 2 }, { age: 3 }];
}

最新更新