问题
I've got an API call that I need to make multiple times as the API doesn't support requests for multiple items. What I have written so far ends up in an endless loop of sending GET requests to the server. I believe I don't understand the nature of Observables in the below example. My assumption is that each call in the while loop subscribes to a new single object and that when it is resolved it will be placed in the array. How can I modify the below code to achieve what I want?
getSingle(): Observable<Single> {
return this.http.get(this.url, this.options)
.map((r: Response) => r.json().data as Single);
}
getMultiple(num: number): Single[] {
let multiple: Single[] = [];
let i = 0;
while (i < num) {
this.getSingle().subscribe(single => {
multiple.push(single);
console.log('Success');
i++;
}, err => {
console.log('Failure');
});
}
return multiple;
}
回答1:
Using the while
loop to make multiple asynchronous HTTP requests, and then subscribe to all of them separately should be avoided in order not to have many Observable
connections opened. We can use Observable.forkJoin operator instead.
This is how the implementation should look like:
getSingle(singleUrl: string): Observable<Single> {
return this.http.get(singleUrl, this.options)
.map((r: Response) => r.json().data as Single);
};
getMultiple(): Observable<Array<Single>> {
let singleUrls = ['singleUrl1', 'singleUrl2', 'singleUrl3']; // can be replaced with any 'Single' identifier
let singleObservables = singleUrls.map((singleUrl: string, urlIndex: number) => {
return this.getSingle(singleUrl)
.map(single => single as Single)
.catch((error: any) => {
console.error('Error loading Single, singleUrl: ' + singleUrl, 'Error: ', error);
return Observable.of(null); // In case error occurs, we need to return Observable, so the stream can continue
});
});
return Observable.forkJoin(singleObservables);
};
this.getMultiple().subscribe(
(singles: Array<Single>) => {
console.log(singles); // [Single, Single, Single];
// In case error occured e.g. for the 'singleUrl' (our 'Single' identifier) at position 1,
// Output wil be: [Single, null, Single];
}
);
Hope this helps!
回答2:
Ideally you would only subscribe once in the constructor since a subscribe block can be called many times and then use an RxJS subject and next() it inside the loop
However, a quick fix if you don't care too much is to:
this.getSingle().first().subscribe
you will need to import the first operator. This will ensure subscribe only is called once only. that way you can sub many times no worries.
I'm guessing the reason you are getting infinite HTTP request is that you failure block is being hit and you need to do ...
}, err => {
i++;
console.log('Failure');
});
来源:https://stackoverflow.com/questions/41619312/send-multiple-asynchronous-http-get-requests