Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make HTTP calls inside a loop and wait for one to finish before making another?

I have an array of items which on each element I want to make an HTTP call, wait for it to finish, then make another call, only one at a time.

I tried:

index(item) {
   return this.service.index(item).pipe(
      map(response => {
         // handle success case
      }),
      catchError(error => {
         // handle error case
      })
   )
}

async processArray(array) {
  const promises = array.map(item => this.index(item));
  await Promise.all(promises);
}

proccessArray(array);

Also with NGRX Effects:

@Effect()
effect$ = this.actions$.pipe(
   ofType<action>(actionTypes.action),
   mergeMapTo(this.store.select(getMyArray)),
   flatMap((request: any[]) => {
       return zip(...request.map(item => {  
         return this.service.index(item).pipe(
               map(response => {
                  // handle success case
               }),
               catchError(error => {
                  // handle error case
               })
            )
         }))
      }),
   );

Also tried doing it in for and forEach loops but they fire all the requests at once. How could I achieve this?

like image 943
Ahmet Ömer Avatar asked Dec 25 '18 13:12

Ahmet Ömer


People also ask

How do you loop API calls?

Run them sequentially with async and await :Loop over the sidArr array and call the messages and update method for each item in the array. Store the returned Promise in a new array. You can wait for all promises in an array to finish with the static Promise. all function.

Does JavaScript wait for for loop to finish?

JavaScript Promises in For Loops. To use Javascript promises in a for loop, use async / await . This waits for each promiseAction to complete before continuing to the next iteration in the loop. In this guide, you learn how async/await works and how it solves the problem of using promises in for loops.


1 Answers

If you are using promises and want to wait for each promise to resolve before another call is made then (1) you should not use Promise.all as this will wait til all requests are resolved and (2) you need to use a plain old for-loop which enables you to wait for async operations within the loop.

async processArray(array) {
  for(var i = 0; i < array.length; i++){
    await yourServiceCall();
  }
}

As a sidenote: Since you are using async-await, don't forget to convert your observables to promises.

If you want to move away from promises (and async-await) and rely on pure RxJS instead, have a look at concatMap:

Projects each source value to an Observable which is merged in the output Observable, in a serialized fashion waiting for each one to complete before merging the next.

For example:

import { from } from 'rxjs/observable/from';

ngOnInit() {
  from(myArray)
    .pipe(concatMap(el => yourServiceCall(el)))
    .subscribe(/* your logic */);
}
like image 81
B12Toaster Avatar answered Oct 02 '22 08:10

B12Toaster