From functional programming we all know map and flatmap. With reactive programming just flattening is not enough information. We have to make a decision about what to do when either observable emits the next element of completes. We have the following choices:

  • mergeMap — deciding not to do anything, we just keep subscribing to every new observable that comes in.
  • switchMap — unsubscribing from the last mapped observable, when the new one arrives.
  • concatMap—queuing up every new Observable, and subscribing to a new observable only when the last observable completes.
  • exhaustMap— ignores (and never subscribe to) any new mapped Observable while the current Observable is still emitting values.

MergeMap

With this flattening strategy you choose to subscribe to all new observables, taking in all new elements. Here is an example:

const socialMediaTrend$ = from(['Facebook', 'Instagram'])
  .pipe( 
     tap(media => console.log(`*** "${media}" is hot now ***`) 
   )
);

socialMediaTrend$.pipe(
  mergeMap(media => media.getPostsObservable())
).subscribe(post => console.log(post));

// CONSOLE:
// *** "Facebook" is hot now *** 
// Facebook post #1 
// Facebook post #2
// *** "Instagram" is hot now ***
// Instagram post #1
// Facebook post #3 (<-- still happening)
// Instagram post #2

SwitchMap

With this flattening strategy you choose to unsubscribe to the first observable when the next one comes in. Like this:

const socialMediaTrend$ = from(['Facebook', 'Instagram'])
  .pipe( 
     tap(media => console.log(`*** "${media}" is hot now ***`) 
   )
);

socialMediaTrend$.pipe(
  switchMap(media => media.getPostsObservable())
).subscribe(post => console.log(post));

// CONSOLE:
// *** "Facebook" is hot now *** 
// Facebook post #1 
// *** "Instagram" is hot now ***
// Instagram post #1
// Instagram post #2
// Instagram post #3

Now you’ve seen the difference between mergeMap and switchMap the rest of the flattening strategies are up to you to explore.