In RxJS what is the difference between putting a mergeMap in a switchMap vs putting a mergeMap after a switchMap?

71 Views Asked by At

I don't understand the difference between these two chunks of code, I would expect identical behavior. The first one has a groupBy and mergeMap after the switchMap. The second one has them inside the switchMap.

const arraySubject = new Subject();

arraySubject.pipe(
  switchMap((arr) => from(arr)),
  groupBy((elem) => elem.type),
  mergeMap((group) => group.pipe(toArray()))
).subscribe((arrGroups) => {
  // nothing gets logged
})

arraySubject.next([{name: 'Bill', type: 'user'}, {name: 'Jane', type: 'admin'}, {name: 'John', type: 'user'}, {name: 'Ann', type: 'admin'}])

Now if I put the groupBy and mergeMap in the pipe of the from(arr) everything works.

const arraySubject = new Subject();

arraySubject.pipe(
  switchMap((arr) => 
    from(arr).pipe(
      groupBy((elem) => elem.type),
      mergeMap((group) => group.pipe(toArray()))))
).subscribe((arrGroups) => {
  arrGroups === [
   {name: 'Bill', type: 'user'}, 
   {name: 'John', type: 'user'}
  ], [
   {name: 'Jane', type: 'admin'}, 
   {name: 'Ann', type: 'admin'}] //true
})

arraySubject.next([{name: 'Bill', type: 'user'}, {name: 'Jane', type: 'admin'}, {name: 'John', type: 'user'}, {name: 'Ann', type: 'admin'}])

In the first chunk of code I just guessed that groupBy would simply group the elements by type then pass two observables (in this case) to the mergeMap which will then convert those two observables to an Array. In my opinion the second piece of code would do the exact same thing? But for some reason the first one does not work. Why is the first one not working, and the second one working?

1

There are 1 best solutions below

2
On

The issue here is that your arraySubject never completes. So toArray() doesn't know when to emit the collected values.

In the second example, from(arr) is the source (instead of the subject) which does complete and lets toArray() emit the buffered values.


Update 01:

Why does from complete and arraySubject does not? Does from just complete when it gets to the end of an array?

In short: yes, exactly this.

To expand on that a bit:

const numStream$ = from([1,2,3,4])

is the similar to (I say similar, since one is "hot" and one is "cold". If nobody is subscribed to the subject when it emits, the value is lost).

const sub = new Subject<number>();
sub.next(1);
sub.next(2);
sub.next(3);
sub.next(4);
sub.complete();

That is, when you pass an array to from(), it will emit each element of the array and then signal the the entire array's elements have been emitted by emitting a complete

A Subject must be completed explicitly, since it doesn't know if you plan to continue emitting (via subject.next()) some time in the future. It must assume it may still get a value until it's explicitly told that it will not.