I am not Typescript, Javascript or frontend developer at all. I have inherited Angular 13 project. There is a function returning Observable<Dto[]>
. I see something along this lines in the code:
this.service.getStuff(arg).pipe(
mergeMap(x => x),
concatMap(y => { return this.service.getOtherStuff(x.subObj.id).pipe(
map(v => ({ obj1: y, obj2: v})));
})
).subscribe(
// ... do something with results
I understand what it does and why it does that, but I can't for the life of me understand why would mergeMap
turn an array into a stream of separate values. Documentation says only that mergeMap
:
Projects each source value to an Observable which is merged in the output Observable
My understanding is that source value
in this case is Dto[]
, so projection should be Observable<Dto[]>
, not a list of Observables created from separate values in the array.
I suspected that maybe this maneuver is done later, but putting tap
with console.log
around mergeMap
shows that input is indeed an array and output is a stream objects.
So what is happening and why? And why isn't it explained in the documentation while we're at it.
CodePudding user response:
The issue here is that you are using mergeMap
not how it is normally intended. The map operators like mergeMap
or switchMap
expect an Observable (or a Promise) as the return value. But you are just returning the plain array. It seems like mergeMap
sees that this is not an Observable and wraps it in a from
operator. This creates an Observable from the array where each element emits individually.
If you do not want this behavior, wrap your value in of
.
mergeMap(x => of(x))
But really this mergeMap
does not have any effect either way. Why are you using this do-nothing function here? If you don't plan to return an Observable, why not use a map
?
CodePudding user response:
This is intended behavior. If you look at the documnetation it says that the project
function needs to return ObservableInput
and not just Observable
. In fact, all RxJS operators that expect an Observable as a parameter will work with any ObservableInput
.
ObservableInput
can be for example an Observable (obviously), async generator, an array or a Promise.
So using mergeMap(x => x)
is really only used to unwrap the array and is equivalent to mergeMap(x => from(x))
. Maybe more clean solution would be using just mergeAll()
operator that is intended to be used with higher-order Observables.