Angular rxjs call http requests in batches with a delay

Viewed 51

I have an array of subscriptions :

const partsArray = parts.map(item => this.partsService.deletePart(item.id));

Then I call a forkJoin on subscriptions and delete them all at once :

  forkJoin(partsArray).subscribe({
    error: (error: ApiError) => {
      
    },
    complete: () => {
     
    }
  });

The problem is that it could be 10 or 100, so I need to batch them and make a delay every 10.

10 API CALLS 
Delay of 500ms
10 API calls 
Delay of 500ms

How can I make it with rxjs ?

3 Answers

If you have millions of parts, you can chunk the array ahead of time.


function chunk(arr, chunkSize) {
  if (chunkSize <= 0) throw "Invalid chunk size";
  let v = [];
  for (let i=0,len=arr.length; i<len; i+=chunkSize) {
    v.push(arr.slice(i,i+chunkSize));
  }
  return v;
}

const delayObs = timer(500).pipe(ignoreElements());

// An array of observables
const partsArray = parts.map(item => this.partsService.deletePart(item.id));

const partsChunked = chunk(partsArray, 10);

const apiResultsChunked = from(partsChunked).pipe(
  concatMap(parts => concat(forkJoin(parts), delayObs))
);

apiResultsChunked.subscribe({
  next: console.log,
  error: (error: ApiError) => {
    
  },
  complete: () => {
   
  }
});

You can simplify this a bit if you use RxJS buffer instead of pre-chunking your array.

from(
  parts.map(item => this.partsService.deletePart(item.id))
).pipe(

  bufferCount(10),
  concatMap(parts => concat(
    forkJoin(parts), 
    timer(500).pipe(ignoreElements())
  ))

).subscribe({
  next: console.log,
  error: (error: ApiError) => {},
  complete: () => {}
});

Just like this

from(parts).pipe(
  map(({ id }) => this.partsService.deletePart(id)),
  bufferCount(10),
  concatMap((apis) => forkJoin(apis).pipe(delay(500)))
).subscribe(...);
Related