Angular等待Http请求响应或者Observable完成

假设一个场景,我们需要从服务端请求API1得到一组关于学生成绩的数据,然后根据返回的数据进行判断如果返回成绩为60,则请求API2,并将成绩100,不为60时,成绩10最终返回经过API1和API2两次处理的结果。

问题重现

如果我们整个流程通过Obvervable来模拟,可以实现下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
reproduce(): Observable<Student[]> {
return this.getStudents().pipe(
mergeMap((result) => {
if (result) {
result.map((rr) => {
if (rr.score == 60) {
this.client
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.subscribe((res) => {
console.log(res);
rr.score = rr.score + 100;
});
} else {
rr.score = rr.score * 10;
}
return rr;
});
}
return of(result);
})
);
}
reproduceTest() {
this.getStudents()
.pipe(
mergeMap((result) => {
if (result && result.length > 0) {
result.forEach((s) => console.log(s.score));
}
return of([]);
})
)
.subscribe();
}
getStudents(): Observable<Student[]> {
return of(this.students());
}
students(): Student[] {
return [{ score: 50 }, { score: 60 }, { score: 70 }];
}

这里执行完成后,我们会发现,返回的结果为50,60,70,而我们正常期望的结果应该是5000,600,700,这个问题的关键在于of直接返回了结果result,导致没有等待map完成输出正确的结果。

通过创建Obvervable分布返回计算结果

关于上面的问题,一种解决方案就是创建Obvervable对象并分布返回计算后的结果,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
createObvervableSolution(): Observable<Student[]> {
return this.getStudents().pipe(
mergeMap((result) => {
return new Observable<Student[]>((subscriber) => {
if (result) {
result.map((rr) => {
if (rr.score == 60) {
this.client
.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.subscribe((res) => {
console.log(res);
rr.score = rr.score * 100;
subscriber.next([rr]);
});
} else {
rr.score = rr.score * 10;
subscriber.next([rr]);
}
});
}
});
})
);
}

通过上面的方式,我们会得到500,700,6000, 顺序不一致主要是因为在60的时候,我们需要等待Http请求完成,会花费时间。

通过Async Await实现

关于将Observable转化为Promise,我们可以通过toPromise实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async async_await_SolutionTest() {
var result = await this.async_await_Solution();
result.forEach((student) => {
console.log(student.score);
});
}
async async_await_Solution(): Promise<Student[]> {
var students = await this.getStudents().toPromise();
students.forEach(async (student) => {
if (student.score == 60) {
var res = await this.client.get(
'https://api.coindesk.com/v1/bpi/currentprice.json'
);
console.log(res);
student.score = student.score * 100;
} else {
student.score = student.score * 10;
}
});
return students;
}

在线测试

引用

发布