I have this code:
https://stackblitz.com/edit/so-74114000-n5t8dl?devtoolsheight=100&file=index.ts:L30
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.
CodePudding user response:
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!