I have a queue of tasks (20 in length) where each tasks is an ajax request to be invoked .
I want to :
1) Create chunks of 5 ( 20/5 =4 chunks)
2) Execute each chunk where each item in chunk will be executed with delay of 1000 ms.
3) When each chunks item complete , wait 3 seconds .
So :
1....2....3....4....5.....................3sec..........
6....7....8....9....10..................... 3sec.......... ... 11....12....13....14....15..................... 3sec..........
16....17....18....19....20
I did manage to do something close :

With :
from(this.httpCodes) .pipe(bufferCount(5), concatMap((i, y) => from(i).pipe(mergeMap(f => { this.httpCodes[f.index].wasExecuted = true; return this.ajaxAlike(f.data).pipe( catchError(() => { return of(-1) }), map((r) => ({ res: r, data: f })) ) }) ,delay(3000) )), )
But it doesn't executed as I intended. I don't see delays between each item in chunk
Question:
Why do I see so many requests , And how can I change my code so that each item in a chunk will be executed with a 1 sec delay (green should be appear after each second) , and - after each chunk , wait 3 seconds?
Online Demo
The delay operator delays an emitted item. It seems like you expect it to emit the item and then 'sleep' for 3 seconds before emitting the next. To achieve this you can concat an empty delayed observable.
You can create the following pipeable sleep operator:
const sleep = ms => concat(Rx.Observable.empty().pipe(delay(ms)))
And use it as follows:
const {concatMap, concat, delay, bufferCount} = Rx.operators; const sleep = ms => concat(Rx.Observable.empty().pipe(delay(ms))); const ajaxAlike = call => Rx.Observable.of(call).pipe(delay(500)); Rx.Observable.range(0, 20).pipe( bufferCount(5), concatMap(calls => Rx.Observable.from(calls).pipe( concatMap(call => ajaxAlike(call).pipe(sleep(1000))), sleep(3000) ) ) ) .subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.7/Rx.js"></script>
EDIT: Ok, I guess now I see what you mean. I updated the fiddle, so that all chunk-parts get executed in parallel, but the chunks wait on each other to complete. So this should do the trick:
const chunkSize = 5; const requestsWithDelay = httpRequests.map(obs => obs.delay(1000)); let chunks = []; for (let i = 0; i < requestsWithDelay.length; i += chunkSize) { chunks.push(requestsWithDelay.slice(i, i + chunkSize)); } const chunkedRequests = chunks.map(chunk => Rx.Observable.forkJoin(...chunk).delay(3000)); const parallelChunkRequest = Rx.Observable.concat(...chunkedRequests); parallelChunkRequest.subscribe();
Original Answer:
Something like this would give you the desired delays (given httpRequests as an array of observables):
const requestsWithDelay = httpRequests.map((obs, idx) => { let msDelay = 1000; if ((idx + 1) % 5 === 0 && idx < httpRequests.length - 1) { msDelay = 3000; } return obs.delay(msDelay); }); const request = Rx.Observable.concat(...requestsWithDelay);
This should work, but there would not be "actual" chunks of observables. The requests in each chunk would not be executed in parallel (like with using mergeMap), but successively.
To get the abservable of httpRequests you could something like this (but without the delay in the pipe):
const httpRequests = this.httpCodes.map(data => this.ajaxAlike(data));
But if you want the chunks to execute in parallel you could do something like this:
let chunks = []; for (let i = 0; i < requestsWithDelay.length; i += 5) { chunks.push(requestsWithDelay.slice(i, i + 5)); } const chunkedRequests = chunks.map(chunk => Rx.Observable.concat(...chunk)); const parallelChunkRequest = Rx.Observable.merge(...chunkedRequests);
I created a demo Fiddle
But why do you need the 3 seconds delay after each chunk, if they get executed in parallel and don't wait for each other?