我试图在我的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]);
之前返回。
我已经尝试了很多方法,如.toPromise
和async 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 }];
}