Multiple Sequential API calls in Angular 4

2019-05-03 08:23发布

问题:

I have an array of image objects.

console.info('gallery', galleryArray);

The length of this array can be different. I have to make a POST request on every item of this array. The next request must be executed only after previous request has finished.

So I tried to make an array of Observable requests like this:

  let requests: Observable<Response>[] = [];
  galleryArray.forEach((image) => {
    requests.push(this._myService.uploadFilesImages(image));
  });

  console.info(requests);

My service looks like this:

uploadFilesImages(fileToUpload: any): Observable<any> {
  const input = new FormData();
  input.append('image', fileToUpload);
  return this.uploadHttp.post(`${this.endpoint}`, input)
  .map(
    (res: Response) => res.json()
  );
}

The question is how to perform those requests, so that every api call goes only after previous has finished? Help please. I'm new to Angular.

回答1:

You are looking for the concatMap operator:

Example

const apiRoot = 'https://jsonplaceholder.typicode.com/';
const urls = [];
for (let i = 0; i < 500; i++) {
  urls.push(apiRoot + 'posts/' + (i + 1));
}
Observable.of(...urls)
  .concatMap((url: string) => this.http.get(url))
  .subscribe((result) => console.log(result));

The concatMap operator only emits after the current iterated on observable is complete. You get the results of the individual calls in the the subscribe block.

In your particular case:

 Observable.of(...galleryArray)
  .concatMap((image) => this._myService.uploadFilesImages(image))
  .subscribe((result) => console.log(result));


回答2:

You can use async / await for that purpose with the Promise resolve:

let requests: Observable<Response>[] = [];
galleryArray.forEach((image) => {
    await new Promise(resolve => {
        this._myService.uploadFilesImages(image)
            .subscribe(result => { 
                requests.push(result);         
                // resolve the promise once we have a result
                resolve();
            });
    });    
});

// This will only be called once all the api calls have been made
console.info(requests);

Make sure you put async behind the method where you are executing this code. Link to my answer for a similar question.