Qual é a diferença entre flatmap e switchmap no RxJava?


149

A definição de switchmap para rxjava doc é bastante vaga e está vinculada à mesma página que o flatmap. Qual é a diferença entre os dois operadores?


1
Sobre o link para a mesma página que o flatmap . Isso é mesmo verdade. Mas role para baixo até a seção Informações específicas do idioma e abra um operador interessante. Eu acho que isso deve ser feito automaticamente a partir do sumário, mas ... Você também pode ver a mesma imagem em javadoc .
Ruslan Stelmachenko

Respostas:


180

De acordo com a documentação ( http://reactivex.io/documentation/operators/flatmap.html )

o switchMapé como o flatMap, mas só emitirá itens do novo observável até que um novo evento seja emitido a partir da fonte observável.

O diagrama de mármore mostra bem. Observe a diferença nos diagramas:

Na switchMapsegunda emissão original ( mármore verde ) não emite sua segunda emissão mapeada ( quadrado verde ), desde que a terceira emissão original ( mármore azul ) começou e já emitiu sua primeira emissão mapeada ( diamante azul ). Em outras palavras, apenas a primeira das duas emissões verdes mapeadas acontece; nenhum quadrado verde é emitido porque o diamante azul o venceu.

Em flatMap, todos os resultados mapeados serão emitidos, mesmo que sejam "obsoletos". Em outras palavras, a primeira e a segunda das emissões verdes mapeadas acontecem - um quadrado verde seria emitido (se usassem a função de mapa consistente; como não o fizeram, você verá o segundo diamante verde, mesmo que seja emitido após o primeiro diamante azul)

switchMap no switchMap, se o observável original emitir algo novo, as emissões anteriores não produzirão mais observáveis ​​mapeados;  essa é uma maneira eficaz de evitar resultados obsoletos

flatMap

no switchMap, se o observável original emitir algo novo, as emissões anteriores não produzirão mais observáveis ​​mapeados;  essa é uma maneira eficaz de evitar resultados obsoletos


4
Obrigado, o diagrama é muito útil. Você conhece um exemplo do mundo real em que o switchMap seria usado?
Julian Go

1
@JulianGo, há um exemplo aqui: github.com/samuelgruetter/rx-playground/blob/master/… Ele usa .map(func).switch, mas é o mesmo que .switchMap(func).
Samuel Gruetter

2
Caso alguém ainda precise de um exemplo real do switchMap, ele pode seguir este link e ele entenderá quando usar o swicthMap em vez do flatMap.
hermannovich

2
Para um exemplo usando SwitchMap de Ben Lesh usando RxJs5 - ver minutos 25-26 aqui - youtube.com/watch?v=3LKMwkuK0ZE para mim, flatmap já foi entendido ...
arcseldon

7
O diagrama de mármore mostra bem? O que? Eu acho que se você já entende switchmap talvez.
precisa saber é o seguinte

166

Me deparei com isso ao implementar a "pesquisa instantânea" - ou seja, quando o usuário digita em uma caixa de texto e os resultados aparecem quase em tempo real a cada toque de tecla. A solução parece ser:

  1. Tem um assunto, como PublishSubject of String
  2. Na caixa de texto, alterar retorno de chamada, chame .onNext (texto)
  3. aplique o filtro .debounce para classificar o limite de consultas do servidor
  4. aplique .switchMap para executar uma consulta ao servidor - obtendo o termo de pesquisa e retornando Observable of SearchResponse
  5. aplicar .subscribe com um método que consome o SearchResponse e atualiza a interface do usuário.

Com o flatMap, os resultados da pesquisa podem ficar obsoletos, pois as respostas da pesquisa podem ficar fora de ordem. Para corrigir isso, o switchMap deve ser usado, pois garante que um observável antigo seja cancelado quando um novo for fornecido.

Portanto, em resumo, o flatMap deve ser usado quando todos os resultados importam, independentemente de seu tempo, e o switchMap deve ser usado quando apenas resultados do último assunto observável.


Você pode verificar este exemplo no GitHub
Cabezas

95

Nenhuma discussão flatMap é concluída sem comparar e contrastar com switchMap, concatMape concatMapEager.

Todos esses métodos usam um Func1que transforma o fluxo em Observables que são então emitidos; a diferença é quando os Observables retornados são inscritos e não inscritos e se e quando esses as emissões desses Observables são emitidas pelo ____Mapoperador em questão.

  • flatMapassina o maior número Observablepossível de s emitidos . (É um número dependente da plataforma. Por exemplo, um número mais baixo no Android) Use-o quando a ordem NÃO for importante e você desejar emissões o mais rápido possível.
  • concatMapassina o primeiro Observablee só assina o próximo Observablequando o anterior for concluído. Use isso quando a ordem for importante e você desejar economizar recursos. Um exemplo perfeito é adiar uma chamada de rede verificando primeiro o cache. Isso geralmente pode ser seguido por um .first()ou .takeFirst()para evitar um trabalho desnecessário.

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

  • concatMapEagerfunciona da mesma forma, mas assina o maior número possível (dependendo da plataforma), mas só será emitido quando o anterior Observablefor concluído. Perfeito quando você tem muito processamento paralelo que precisa ser feito, mas (ao contrário do flatMap) deseja manter a ordem original.

  • switchMapassinará o último Observableque encontrar e cancelará a assinatura de todos os Observables anteriores . Isso é perfeito para casos como sugestões de pesquisa: depois que um usuário altera sua consulta de pesquisa, a solicitação antiga não tem mais interesse e, portanto, é cancelada a inscrição, e um ponto de extremidade da API bem comportado cancelará a solicitação de rede.

Se você está retornando Observables que não possuem subscribeOnoutro encadeamento, todos os métodos acima podem se comportar da mesma forma. O comportamento interessante e útil surge quando você permite que os Observables aninhados atuem em seus próprios encadeamentos. Em seguida, você poderá obter muitos benefícios do processamento paralelo e cancelar de maneira inteligente a inscrição ou não a inscrição de Observables que não interessam aos seus Subscribers

  • ambtambém pode ser interessante. Dado qualquer número de Observables, emite os mesmos itens que o primeiro Observablea emitir qualquer coisa. Isso pode ser útil quando você tem várias fontes que podem / devem retornar a mesma coisa e desejam desempenho. por exemplo, classificação, você pode fazer ambuma classificação rápida com uma classificação de mesclagem e usar o que for mais rápido.

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- todas as explicações switchMap vs flatMapque encontrei antes, perderam esse aspecto importante, agora tudo está mais claro. Obrigado.
Andy Res

55

O switchMap já foi chamado flatMapLatest no RxJS 4.

Basicamente, apenas transmite os eventos do Observable mais recente e cancela a inscrição do anterior.


@EpicPandaForce Embora seja inconsistente com o combineLatest, que emite os valores mais recentes sempre que uma fonte observável emite (não emite uma vez).
Michael Fry

2
Em parte, o motivo é chamado switchMap, porque você pode implementar esse operador usando o.map (...). Switch (). Embora eu imaginasse que seria o mapSwitch, que não parece sair tão facilmente da língua.
Niall Connaughton

7

Map, FlatMap, ConcatMap e SwitchMap aplicam uma função ou modificam os dados emitidos por um Observable.

  • O mapa modifica cada item emitido por uma fonte observável e emite o item modificado.

  • O FlatMap, SwitchMap e ConcatMap também aplicam uma função em cada item emitido, mas, em vez de retornar o item modificado, ele retorna o próprio Observable, que pode emitir dados novamente.

  • O trabalho do FlatMap e ConcatMap é praticamente o mesmo. Eles mesclam itens emitidos por vários observáveis ​​e retornam um único observável.

  • A diferença entre o FlatMap e o ConcatMap é a ordem em que os itens são emitidos.
  • O FlatMap pode intercalar itens durante a emissão, ou seja, a ordem dos itens emitidos não é mantida.
  • O ConcatMap preserva a ordem dos itens. Mas a principal desvantagem do ConcatMap é que ele precisa aguardar que cada Observável conclua seu trabalho, para que o assíncrono não seja mantido.
  • O SwitchMap é um pouco diferente do FlatMap e do ConcatMap . O SwitchMap cancela a assinatura do Observable de origem anterior sempre que um novo item é emitido, sempre emitindo os itens do Observable atual.

1

Se você está procurando um código de exemplo

/**
 * 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);

}

Você pode ver mais exemplos aqui https://github.com/politrons/reactive


4
Mas você sente falta do recurso principal do switchMap que o distingue do flatMap - apenas os assuntos Observáveis ​​mais recentes, ao cancelar a assinatura dos anteriores.
Artem Novikov

3
Neste exemplo, quando você substituir switchMappor flatMapele funcionará exatamente da mesma forma.
Piotr Wittchen

1

Aqui está a mais uma - 101 longa linha exemplo . Isso explica a coisa para mim.

Como foi dito: ele obtém o último observável (o mais lento, se você preferir) e ignora o resto.

Como um 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

Você vê o A ignorado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.