Angular map 等待 Observable 完成
Angular map wait Observable to complete
我正在尝试在我的 Observable
函数中发送 httpclient,它将 运行 没有 HttpClient Complete。
这是一个演示代码,用于复现
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]);
之前 return。
我尝试了很多方法,比如.toPromise
,async await
,但都没有成功。
您可以在下面创建一个测试版本:
https://stackblitz.com/edit/save-file-to-drive-7dawzd?file=src/app/app.component.ts
根据您的预期结果,您需要先完成 api 调用,然后再打印 Student[0]。
您的代码存在的问题:
- 您正在订阅一个 api 电话,您不在等待
完成,因此
console.log(result[0])
在 console.log(res);
之前先打印,因为 api 调用尚未完成。
我使用了几个 RXJS 运算符来得到你想要的。
mergeMap
压平内部可观察对象
of
将 student 数组转换为 observable
map
将当前数组转换成一个新的数组,其对应的新年龄
forkJoin
- 我们将多个请求包装到一个可观察对象中,并且仅当所有请求都收到响应时才会 return。
这当然只是一种方法,可能还有其他更好的方法。
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 }];
}
我正在尝试在我的 Observable
函数中发送 httpclient,它将 运行 没有 HttpClient Complete。
这是一个演示代码,用于复现
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]);
之前 return。
我尝试了很多方法,比如.toPromise
,async await
,但都没有成功。
您可以在下面创建一个测试版本:
https://stackblitz.com/edit/save-file-to-drive-7dawzd?file=src/app/app.component.ts
根据您的预期结果,您需要先完成 api 调用,然后再打印 Student[0]。
您的代码存在的问题:
- 您正在订阅一个 api 电话,您不在等待
完成,因此
console.log(result[0])
在console.log(res);
之前先打印,因为 api 调用尚未完成。
我使用了几个 RXJS 运算符来得到你想要的。
mergeMap
压平内部可观察对象of
将 student 数组转换为 observablemap
将当前数组转换成一个新的数组,其对应的新年龄forkJoin
- 我们将多个请求包装到一个可观察对象中,并且仅当所有请求都收到响应时才会 return。
这当然只是一种方法,可能还有其他更好的方法。
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 }];
}