如何在 Angular 4 中等待并从循环中获取每个 HttpClient 服务调用的响应
How to wait and get response for each HttpClient service call from a loop in Angular 4
我有一种情况需要 运行 循环并获取相应项目的 描述。然后连同项目 ID 和其他信息,我必须将获取的 description 包含在数据表中。
addDescription(){
this.arrayOfItems.forEach(element => {
// CALL a function which will make a service call
this.fetchDescription(element);
//CODE TO DECLARE AN INTERFACE TO ASSIGN RESPECTIVE VALUES. eg.
// ITEM_ID : element.id,
// ITEM_DEF : this.fetchedDescription.join("\n")
}
函数体:
fetchDescription(elementToFetchDesc){
//Declaring HTTPPARAMS in PassingParams variable
this.componentService.getDesc(PassingParams)
.subscribe((response: HttpResponse<any>) => {
if(response.status ==200){
this.fetchedDescription = reponse.body.output.slice(6,-1);
}
//Code if response status is NOT 200
}
在 componentService
服务中:
construcutor(private httpConn: HttpClient){}
getDesc(Params){
// Declare URL
return this.httpConn.get(URL, {params: Params, observe: 'response'});
}
问题:
因为它在循环中 运行 并且订阅是异步调用,所以,在 运行 在 forEach
中循环之后它就出来了。因此,description 未分配给界面中的变量 (ITEM_DEF
)。
为了解决这个问题,我对使用 promise
进行了一些改动。
在服务中我添加了:
import 'rxjs/add/operator/toPromise';
并将服务方法更新为:
return this.httpConn.get(URL, {params: Params, observe: 'response'})
.toPromise(); // converted observable into promise
组件也发生了变化:
fetchDescription
函数内部:
将 .subscribe
替换为 .then
但问题依然存在。请让我知道我在执行此逻辑时哪里做错了。
解决方案是将 observable 转换为 promise 但不使用 then!
示例:
这是您发送请求的服务函数:
myRequest(num) {
return this.http.get('http://someUrl.com/' + num).toPromise();
}
这是发送组件中所有请求的函数class:
async sendAll() {
let response = [];
for(let i = 0; i < 5; i++) {
response[i] = await this.myService.myRequest();
}
// Got all the results!
}
解决方案:
函数体:
fetchDescription(elementToFetchDesc): Observable<string> {
//Declaring HTTPPARAMS in PassingParams variable
return this.componentService.getDesc(PassingParams)
.map((response: HttpResponse<any>) => {
if(response.status ==200){
return reponse.body.output.slice(6,-1);
}
});
}
}
通话:
this.fetchDescription(element).subscribe((description: string) => {
ITEM_ID : element.id,
ITEM_DEF : description
});
为此你应该使用 rxjs.
checkStatus(url: string, id: string): Observable<string> {
const trigger$ = new Subject<string>();
const time = Date.now();
return trigger$.asObservable().startWith(url).concatMap((u) => {
return this.ping(u).map(() => {
trigger$.complete();
return id;
}).catch((err) => {
trigger$.next(u);
return Observable.empty<any>();
});
});
}
protected ping(url: string): Observable<any> {
return this.http.get(url)
.catch(err => Observable.throw(err));
}
此处 concatMap 运算符将仅在第一个已完成时触发下一个可观察对象,即第一个 API 调用的响应可用。每当您在 trigger$ 主题上调用方法 complete()
时,它都会完成 observable 和 API 调用。您可能必须更改调用 complete()
.
的逻辑
我有一种情况需要 运行 循环并获取相应项目的 描述。然后连同项目 ID 和其他信息,我必须将获取的 description 包含在数据表中。
addDescription(){
this.arrayOfItems.forEach(element => {
// CALL a function which will make a service call
this.fetchDescription(element);
//CODE TO DECLARE AN INTERFACE TO ASSIGN RESPECTIVE VALUES. eg.
// ITEM_ID : element.id,
// ITEM_DEF : this.fetchedDescription.join("\n")
}
函数体:
fetchDescription(elementToFetchDesc){
//Declaring HTTPPARAMS in PassingParams variable
this.componentService.getDesc(PassingParams)
.subscribe((response: HttpResponse<any>) => {
if(response.status ==200){
this.fetchedDescription = reponse.body.output.slice(6,-1);
}
//Code if response status is NOT 200
}
在 componentService
服务中:
construcutor(private httpConn: HttpClient){}
getDesc(Params){
// Declare URL
return this.httpConn.get(URL, {params: Params, observe: 'response'});
}
问题:
因为它在循环中 运行 并且订阅是异步调用,所以,在 运行 在 forEach
中循环之后它就出来了。因此,description 未分配给界面中的变量 (ITEM_DEF
)。
为了解决这个问题,我对使用 promise
进行了一些改动。
在服务中我添加了:
import 'rxjs/add/operator/toPromise';
并将服务方法更新为:
return this.httpConn.get(URL, {params: Params, observe: 'response'})
.toPromise(); // converted observable into promise
组件也发生了变化:
fetchDescription
函数内部:
将 .subscribe
替换为 .then
但问题依然存在。请让我知道我在执行此逻辑时哪里做错了。
解决方案是将 observable 转换为 promise 但不使用 then!
示例:
这是您发送请求的服务函数:
myRequest(num) {
return this.http.get('http://someUrl.com/' + num).toPromise();
}
这是发送组件中所有请求的函数class:
async sendAll() {
let response = [];
for(let i = 0; i < 5; i++) {
response[i] = await this.myService.myRequest();
}
// Got all the results!
}
解决方案:
函数体:
fetchDescription(elementToFetchDesc): Observable<string> {
//Declaring HTTPPARAMS in PassingParams variable
return this.componentService.getDesc(PassingParams)
.map((response: HttpResponse<any>) => {
if(response.status ==200){
return reponse.body.output.slice(6,-1);
}
});
}
}
通话:
this.fetchDescription(element).subscribe((description: string) => {
ITEM_ID : element.id,
ITEM_DEF : description
});
为此你应该使用 rxjs.
checkStatus(url: string, id: string): Observable<string> {
const trigger$ = new Subject<string>();
const time = Date.now();
return trigger$.asObservable().startWith(url).concatMap((u) => {
return this.ping(u).map(() => {
trigger$.complete();
return id;
}).catch((err) => {
trigger$.next(u);
return Observable.empty<any>();
});
});
}
protected ping(url: string): Observable<any> {
return this.http.get(url)
.catch(err => Observable.throw(err));
}
此处 concatMap 运算符将仅在第一个已完成时触发下一个可观察对象,即第一个 API 调用的响应可用。每当您在 trigger$ 主题上调用方法 complete()
时,它都会完成 observable 和 API 调用。您可能必须更改调用 complete()
.