I have this code:
https://stackblitz.com/edit/so-74114000-n5t8dl?devtoolsheight=100&file=index.ts%3AL30
import './style.css';
import { of, from, mergeMap, delay, tap, defer, Observable, map, switchMap, combineLatest, } from 'rxjs';
GetIds()
.pipe(mergeMap((x) => x.map((i) => fakeRequest(`#${i}`))))
.pipe(mergeMap((req$) => req$, 3))
.subscribe(
(result) => console.log(`${result} DONE!`),
(error) => console.error(error)
);
function fakeRequest(label: string): Observable<string> {
return defer(() =>
of(label).pipe(
tap(() => console.log(`> Fetching ${label}`)),
delay(Math.random() * 5000 + 1250)
)
);
}
function GetIds(): Observable<number[]> {
return of([1, 2, 3, 4, 5]).pipe(tap((qi) => console.log(`> id ${qi}`)));
}
It's faking a couple web requests with a max of 3 concurrent using mergeMap.
Output:
> id 1,2,3,4,5
> Fetching #1
> Fetching #2
> Fetching #3
#2 DONE!
> Fetching #4
#1 DONE!
> Fetching #5
#4 DONE!
#5 DONE!
#3 DONE!
I am missing one thing: I would like the "DONE" message to appear only at the end, once all the request are done. Currently the "DONE" message is appearing after each request.
Instead of emitting each result as they are received, you can emit an array of all results once the source completes using toArray
:
GetIds().pipe(
mergeMap(x => getUpdateRequests(x)),
mergeMap(req$ => req$, 3),
toArray()
).subscribe(
result => console.log(`${result} DONE!`),
error => console.error(error)
);
Output:
> Fetching #444
> Fetching #1
> Fetching #2
> Fetching #3
> Fetching #4
> Fetching #5
#1,#2,#3,#444,#4,#5 DONE!