¿Cuál es la diferencia entre flatmap y switchmap en RxJava?


149

La definición de rxjava doc de switchmap es bastante vaga y se vincula a la misma página que flatmap. ¿Cuál es la diferencia entre los dos operadores?


1
Acerca de esto enlaza a la misma página que flatmap . Es realmente cierto Pero desplácese hacia abajo hasta la sección Información específica del idioma y abra el operador interesante. Creo que esto debería hacerse automáticamente desde TOC, pero ... También puedes ver la misma imagen en javadoc .
Ruslan Stelmachenko

Respuestas:


180

De acuerdo con la documentación ( http://reactivex.io/documentation/operators/flatmap.html )

the switchMapes como el flatMap, pero solo emitirá elementos del nuevo observable hasta que se emita un nuevo evento desde el origen observable.

El diagrama de mármol lo muestra bien. Observe la diferencia en los diagramas:

En switchMapla segunda emisión original ( mármol verde ) no se emite su segunda emisión mapeada ( cuadrado verde ), ya que la tercera emisión original ( mármol azul ) ha comenzado y ya emitió su primera emisión mapeada ( diamante azul ). En otras palabras, solo ocurre la primera de las dos emisiones verdes mapeadas ; no se emite un cuadrado verde porque el diamante azul lo venció.

En flatMap, se emitirán todos los resultados asignados, incluso si están "obsoletos". En otras palabras, tanto la primera como la segunda de las emisiones verdes mapeadas suceden: se habría emitido un cuadrado verde (si usaran una función de mapa consistente; como no lo hicieron, verá el segundo diamante verde, a pesar de que se emite después el primer diamante azul)

switchMap en switchMap si el observable original emite algo nuevo, las emisiones anteriores ya no producen observables mapeados;  Esta es una manera efectiva de evitar resultados obsoletos

mapa plano

en switchMap si el observable original emite algo nuevo, las emisiones anteriores ya no producen observables mapeados;  esta es una manera efectiva de evitar resultados atrasados


44
Gracias, el diagrama es muy útil. ¿Conoces un ejemplo del mundo real donde se usaría switchMap?
Julian Go

1
@JulianGo hay un ejemplo aquí: github.com/samuelgruetter/rx-playground/blob/master/… Utiliza .map(func).switch, pero es lo mismo que .switchMap(func).
Samuel Gruetter

2
En caso de que alguien todavía necesite un ejemplo del mundo real de switchMap, puede seguir este enlace de enlace y entenderá cuándo usar swicthMap en lugar de flatMap.
hermannovich

2
Para un ejemplo usando SwitchMap de Ben Lesh usando RxJs5 - vea los minutos 25-26 aquí - youtube.com/watch?v=3LKMwkuK0ZE para mí, el mapa plano ya se entendió ...
arcseldon

77
¿El diagrama de mármol lo muestra bien? ¿Qué? Supongo que si ya entiendes switchmap tal vez.
Helzgate

166

Me encontré con esto al implementar la "búsqueda instantánea", es decir, cuando el usuario escribe en un cuadro de texto y los resultados aparecen casi en tiempo real con cada pulsación de tecla. La solución parece ser:

  1. Tener un tema, como PublishSubject of String
  2. En el cuadro de texto cambiar devolución de llamada, invoque .onNext (texto)
  3. aplicar el filtro .debounce para calificar consultas de servidor de límite
  4. aplique .switchMap para realizar una consulta del servidor, tomando el término de búsqueda y devolviendo Observable of SearchResponse
  5. aplique .subscribe con un método que consume SearchResponse y actualiza la IU.

Con flatMap, los resultados de búsqueda podrían ser obsoletos, porque las respuestas de búsqueda pueden volverse fuera de orden. Para solucionar esto, se debe usar switchMap, ya que garantiza que un observable antiguo se da de baja una vez que se proporciona uno nuevo.

Entonces, en resumen, flatMap debe usarse cuando todos los resultados importan, independientemente de su tiempo, y switchMap debe usarse cuando solo resultan de la última materia Observable.


Puede consultar este ejemplo en GitHub
Cabezas

95

Ninguna discusión de flatMap está completa sin comparar y contrastar con switchMap, concatMapy concatMapEager.

Todos estos métodos toman una Func1que transforma la corriente en Observables que luego se emiten; la diferencia es cuando los Observablemensajes devueltos se suscriben y anulan, y en caso Observablede que el ____Mapoperador en cuestión emita las emisiones de esos mensajes .

  • flatMapse suscribe a tantos Observables emitidos como sea posible. (Es un número dependiente de la plataforma. Por ejemplo, un número más bajo en Android) Úselo cuando el pedido NO sea importante y desee emisiones lo antes posible.
  • concatMapse suscribe al primero Observabley solo se suscribe al siguiente Observablecuando se haya completado el anterior. Úselo cuando el pedido sea importante y desee conservar recursos. Un ejemplo perfecto es aplazar una llamada de red comprobando primero el caché. Esto generalmente puede ser seguido por una .first()o .takeFirst()para evitar hacer un trabajo innecesario.

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEagerfunciona de la misma manera, pero se suscribe a la mayor cantidad posible (depende de la plataforma), pero solo se emitirá una vez que se Observablehaya completado lo anterior . Perfecto cuando tiene mucho procesamiento paralelo que debe hacerse, pero (a diferencia de flatMap) desea mantener el orden original.

  • switchMapse suscribirá al último Observableque encuentre y se dará de baja de todos los correos electrónicos anteriores Observable. Esto es perfecto para casos como sugerencias de búsqueda: una vez que un usuario ha cambiado su consulta de búsqueda, la solicitud anterior ya no tiene ningún interés, por lo que se cancela la suscripción y un punto final de Api con buen comportamiento cancelará la solicitud de red.

Si está devolviendo Observablemensajes de correo electrónico que no tienen subscribeOnotro hilo, todos los métodos anteriores pueden comportarse de la misma manera. El comportamiento interesante y útil surge cuando permite que los Observables anidados actúen en sus propios hilos. Entonces se puede obtener obtener una gran cantidad de beneficios de procesamiento en paralelo, de forma inteligente y darse de baja o no suscribirse de Observables que no le interesan a su Subscribers

  • ambTambién puede ser de interés. Dado cualquier número de Observables, emite los mismos elementos que el primero Observableen emitir algo. Eso podría ser útil cuando tiene múltiples fuentes que podrían / ​​deberían devolver lo mismo y desea rendimiento. por ejemplo, ordenar, puede ambordenar rápidamente con una combinación de clasificación y usar el que sea más rápido.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- Cada explicación que switchMap vs flatMapencontré antes, perdí este aspecto importante, ahora todo está más claro. Gracias.
Andy Res

55

switchMap alguna vez se llamó flatMapLatest en RxJS 4.

Básicamente, solo pasa los eventos del último Observable y se da de baja del anterior.


@EpicPandaForce Aunque es inconsistente con combineLatest, que emite los últimos valores siempre que se emite una fuente observable (no se emite una vez).
Michael Fry

2
En parte, la razón por la que se llama switchMap es porque puede implementar este operador usted mismo utilizando o.map (...). Switch (). Aunque entonces me imagino que sería mapSwitch, que no parece salir de la lengua tan fácilmente.
Niall Connaughton el

7

Mapa, FlatMap, ConcatMap y SwitchMap aplica una función o modifica los datos emitidos por un observable.

  • El mapa modifica cada elemento emitido por una fuente Observable y emite el elemento modificado.

  • FlatMap, SwitchMap y ConcatMap también aplica una función en cada elemento emitido, pero en lugar de devolver el elemento modificado, devuelve el Observable mismo que puede emitir datos nuevamente.

  • El trabajo de FlatMap y ConcatMap es prácticamente el mismo. Fusionan elementos emitidos por múltiples observables y devuelve un solo observable.

  • La diferencia entre FlatMap y ConcatMap es el orden en que se emiten los elementos.
  • FlatMap puede intercalar elementos durante la emisión, es decir, el orden de los elementos emitidos no se mantiene.
  • ConcatMap conserva el orden de los artículos. Pero la principal desventaja de ConcatMap es que tiene que esperar a que cada Observable complete su trabajo, por lo que no se mantiene asincrónico.
  • SwitchMap es un poco diferente de FlatMap y ConcatMap . SwitchMap se da de baja de la fuente anterior Observable cada vez que un nuevo elemento comienza a emitirse, por lo que siempre emite los elementos del Observable actual.

1

Si buscas un código de ejemplo

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

Puede ver más ejemplos aquí https://github.com/politrons/reactive


44
Pero se pierde la característica clave de switchMap que lo distingue de flatMap: solo importa el Observable más reciente, mientras se da de baja de los anteriores.
Artem Novikov

3
En este ejemplo, cada vez que cambie switchMapcon el flatMapque va a funcionar exactamente igual.
Piotr Wittchen

1

Aquí está el ejemplo más: 101 líneas de largo . Eso explica la cosa para mí.

Como se dijo: obtiene el último observable (el más lento si se quiere) e ignora el resto.

Como resultado:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

Ves que la A fue ignorada.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.