RXJS mergeMap/flatMap

mergeMap(
  project: function: Observable, 
  resultSelector: function: any, 
  concurrent: number
): Observable

Преобразовать каждое испускаемое значение в наблюдаемый объект.

flatMap - это псевдоним для mergeMap
Если будет активна  только одна внутренняя подписка в конкретный промежуток времени, попробуйте использовать switchMap
Если порядок испускания элементов, подписки для внутренних наблюдаемых являются важными, попробуйте concatMap

Зачем использовать mergeMap?

Этот оператор лучше всего подходит, если нужно наложить каждый элемент потока на внутренний наблюдаемый объект, но необходимо вручную контролировать количество внутренних подписок.

Для экземпляров использующих switchMap каждая внутренняя подписка завершается, когда источник испускает значение, то есть всегда существует только одна активная внутренняя/локальная подписка. Напротив, mergeMap позволяет быть активными нескольким активным локальным подпискам.  И поэтому, один из распространенных вариантов использования mergeMap это запросы, которые не должны быть отменены или прерваны. Если нужно управлять порядком выполнения запросов, то concatMap будет лучшим вариантом.  

Следует помнить, так как mergeMap поддерживает сразу несколько активных локальных подписок, очень легко создать "утечки памяти", создавая долговременные подписки. Примером может служить использование таймеров или событий DOM. В подобных случаях, если вы все же решили использовать mergeMap,  нужно подумать об использовании операторов take и takeUntil для управления  завершением подписки.

Ограничить общее количество внутренних/локальных подписок можно параметром concurrent.

Пример с наблюдаемым  

import {of} from 'rxjs'
import {mergeMap} from 'rxjs/operators'

// отправляем 'hello'
const source = of('hello')

// 
const example = source.pipe(mergeMap(_ => of(`${_} World!`)))

// подписка
const sub = example.subscribe(console.log)

Пример с Promise

import {of} from 'rxjs'
import {mergeMap} from 'rxjs/operators'

// испускаем 'hello'
const source = of('Hello')

// mergeMap также может испускать результат от Promise
const myPromise = _ => new Promise(resolve => resolve(`${_} World from Promise!`))

// наложить на Promise 
const example = source.pipe(mergeMap(_ => myPromise(_)))

Пример использования  resultSelector

import {of} from 'rxjs'
import {mergeMap} from 'rxjs/operators'

/*
 вторым аргументом можно указать функцию (resultSelector), в которую будут переданы: исходное значение и испускаемое значение от локального наблюдаемого объекта или "промиса"
*/

// испускаем 'hello'
const source = of('hello')

// mergeMap может принимать Promise и испускать его значение (resolve) 
const myPromise = _ => new Promise(resolve => resolve(`${_} from Promise!`))

// обработка потока 
const example = source.pipe(
  mergeMap(
    _ => myPromise(_), 
    (valueFromSource, valueFromPromise) => {
      return `source: ${valueFromSource}, promise: ${valueFromPromise}`
    }
  )
)

// 
const sub = example.subscribe(console.log)