Saltar al contenido

flatMap, mergeMap, switchMap y concatMap en rxjs?

Esta es la respuesta más acertada que encomtrarás brindar, pero mírala pausadamente y analiza si se puede adaptar a tu proyecto.

Solución:

Tomando esto de una respuesta anterior:

  • flatMap / mergeMap – crea un Observable inmediatamente para cualquier elemento de origen, todos los Observables anteriores se mantienen vivos
  • concatMap – espera a que se complete el Observable anterior antes de crear el siguiente
  • switchMap – para cualquier elemento de origen, completa el Observable anterior y crea inmediatamente el siguiente
  • exhaustMap – los elementos de origen se ignoran mientras el Observable anterior no se completa

Aquí hay un ejemplo de cómo se comporta cada uno de los operadores cuando la fuente son elementos inmediatos (0, 1, 2, 3, 4) y la función de mapa crea un Observable que retrasa cada elemento en 500 ms:

const  mergeMap, flatMap, concatMap, switchMap, exhaustMap  = Rx.operators;

const example = operator => () =>
  Rx.Observable.from([0,1,2,3,4])
  .pipe(
    operator(x => Rx.Observable.of(x).delay(500))
  )
  .subscribe(console.log, () => , () => console.log(`$operator.name completed`));

const mm = example(mergeMap);
const fm = example(flatMap);
const cm = example(concatMap);    
const sm = example(switchMap);
const em = example(exhaustMap);
.examples > div 
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;


mergeMap
flatMap
concatMap
switchMap
exhaustMap

En el diagrama de mármol de abajo, un flujo fuente que emite a 5 ms, 10ms, 20 ms estarán * Mapeado a un timer(0, 3), limitado a 3 emisiones:

mergeMap vs exhaustMap vs switchMap vs concatMap

Juega con este diagrama de canicas aquí: “mergeMap vs exhaustMap vs switchMap vs concatMap”

Ya teniendo todas estas respuestas increíbles, quería agregar una explicación más visual

Espero que ayude a alguien

@ZahiC, buena respuesta: me gusta el uso de la composición funcional en el código de muestra. Si se me permite, me gustaría tomarlo prestado para ilustrar un par de puntos adicionales utilizando observables cronometrados.

Exterior, interior y control

Estos operadores son todos operadores de transformación como map(), la característica común es que tienen una exterior y interno observable. los key La diferencia es la forma en que el exterior observable control S el interior observable.

Para contrastarlos, mi ejemplo de código los ejecuta en pares, generando valores en el formulario [outerValue,innerValue]. Agregué intervalos a la prueba y cambié el retraso interno para que haya cierta superposición en el tiempo (la fórmula utilizada es delay((5-x)*200)).


mergeMap vs concatMap

Ambos salen todos los valores, la diferencia es la ordenar.

mergeMap – Ordenar por observable interno
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

concatMap – Ordenar por observable externo
[0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1],[4,0],[4,1]

Desde la salida, la emisión externa de mergeMap se puede retrasar en la secuencia, pero concatMap sigue una secuencia de emisión externa estricta.


switchMap vs exhaustMap

Estos dos acelerador La salida.

switchMap – Acelerar por último
[3,0],[4,0],[4,1]

exhaustMap – Acelerar por primera
[0,0],[0,1],[4,0],[4,1]

Desde la salida, switchMap acelera cualquier incompleto interior emite, pero escape aceleradores de mapa siguiente emite hasta que se completen los anteriores.


mergeMap vs switchMap

Agregué esto porque switchmap se usa a menudo en respuestas SO donde realmente se debe usar mergeMap.

mergeMap – Ordenar por observable interno
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

switchMap – Acelerar por último
[3,0],[4,0],[4,1]

La conclusión principal es que la salida de switchMap es impredecible dependiendo del momento del observable interno, por ejemplo, si el interno es un http obtener los resultados pueden depender de la velocidad de conexión.


console.clear()
const  mergeMap, flatMap, concatMap, switchMap, exhaustMap, delay, map, take, toArray  = Rx.operators;

const note = 
  mergeMap:  'Order by inner observable', 
  concatMap: 'Order by outer observable', 
  switchMap: 'Throttle by last', 
  exhaustMap: 'Throttle by first', 

const title = (operator) => 
  const opName = operator.name.replace('$1','')
  return `$opName - $note[opName]`

const display = (x) => 
  return map(y => `[$x,$y]`)

const inner = (x) => Rx.Observable.timer(0,500)
.pipe(
  delay((5-x)*200),
  display(x),
  take(2)
)

const example = operator => () => 
  Rx.Observable.interval(500).take(5)
  .pipe(
    operator(x => inner(x)),
    toArray(),
    map(vals => vals.join(','))
  )
  .subscribe(x => 
    console.log(title(operator))
    console.log(x)
  );
;

const run = (fn1, fn2) => 
  console.clear()
  fn1()
  fn2()

const mmVcm = () => run(example(mergeMap), example(concatMap));
const smVem = () => run(example(switchMap), example(exhaustMap));
const mmVsm = () => run(example(mergeMap), example(switchMap));
.examples > div 
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  padding: 7px 16px;
  display: inline-block;


mergeMap vs concatMap
switchMap vs exhaustMap
mergeMap vs switchMap

Si conservas algún atascamiento y forma de aclararse nuestro sección puedes ejecutar una crónica y con mucho placer lo estudiaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 3 Promedio: 5)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *