26 votes

flatMap, mergeMap, switchMap et concatMap en rxjs ?

Quelqu'un peut-il expliquer la différence entre SwitchMap et FlatMap en termes de Javascript ( dans la perspective d'Angular, rxjs 5) ?

D'après ce que je comprends.

SwitchMap n'émet que la dernière valeur observable et annule l'observable précédent.

flatMap collecte tous les observables individuels et renvoie tous les observables dans un seul tableau sans se soucier de l'ordre des observables. fonctionne de manière asynchrone.

concatMap préserve l'ordre et émet toute valeur observable, travaille de manière synchrone

c'est bien ça ?

comment mergeMap fonctionne différemment d'en haut ?

quelqu'un, veuillez expliquer avec un exemple.

24voto

ZahiC Points 3896

D'après un réponse précédente :

  • platMap/mergeMap - crée immédiatement un Observable pour n'importe quel élément source, tous les Observables précédents sont maintenus en vie
  • concatMap - attend que l'Observable précédent soit terminé avant de créer le suivant
  • switchMap - pour tout élément source, termine l'Observable précédent et crée immédiatement le suivant
  • épuiserMap - les éléments sources sont ignorés tant que l'Observable précédent n'est pas terminé

Voici un exemple du comportement de chacun des opérateurs lorsque la source est constituée d'éléments immédiats (0,1,2,3,4) et que la fonction map crée un Observable qui retarde chaque élément de 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;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>

<div class='examples'>
  <div onClick='mm()'>mergeMap </div>
  <div onClick='fm()'>flatMap</div>
  <div onClick='cm()'>concatMap</div>
  <div onClick='sm()'>switchMap</div>
  <div onClick='em()'>exhaustMap</div>
</div>

16voto

Richard Matsen Points 7624

@ZahiC, réponse cool - j'aime l'utilisation de la composition fonctionnelle dans l'exemple de code. Si je peux me permettre, j'aimerais l'emprunter pour illustrer quelques points supplémentaires en utilisant des observables temporisés.

Extérieur, intérieur et contrôle

Ces opérateurs sont tous opérateurs de transformation comme map() La caractéristique commune est qu'ils ont une extérieur y intérieur observable. La principale différence est la façon dont l'observable externe contrôles l'observable interne.

Pour les contraster, mon exemple de code les exécute par paires, en produisant des valeurs sous la forme de [outerValue,innerValue] . J'ai ajouté des intervalles au test, et modifié le délai interne de manière à ce qu'il y ait un certain chevauchement dans le temps (la formule utilisée est la suivante delay((5-x)*200) ).


mergeMap vs concatMap

Ceux-ci produisent tous deux toutes les valeurs la différence est que commander .

mergeMap - Ordre par observable interne
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

concatMap - Ordre par observable externe
[0,0],[0,1],[1,0],[1,1],[2,0],[2,1],[3,0],[3,1],[4,0],[4,1]

D'après le résultat, l'émission extérieure de mergeMap peut être retardée dans la séquence, mais concatMap suit une séquence d'émission extérieure stricte.


switchMap vs exhaustMap

Ces deux papillon des gaz la sortie.

switchMap - L'accélérateur en dernier lieu
[3,0],[4,0],[4,1]

exhaustMap - L'accélérateur en premier
[0,0],[0,1],[4,0],[4,1]

A partir de la sortie, switchMap étrangle tout incomplet l'intérieur émet, mais les gaz d'échappement étranglent suivant émet jusqu'à ce que les précédentes soient terminées.


mergeMap vs switchMap

Je l'ai ajouté parce que switchmap est souvent utilisé dans les réponses de l'OS alors qu'il faudrait plutôt utiliser mergeMap.

mergeMap - Ordre par observable interne
[0,0],[1,0],[0,1],[2,0],[1,1],[3,0],[2,1],[4,0],[3,1],[4,1]

switchMap - L'accélérateur en dernier lieu
[3,0],[4,0],[4,1]

La principale leçon à retenir est que la sortie de switchMap est imprévisible en fonction du moment de l'observable interne, par exemple si l'observable interne est une http get les résultats peuvent dépendre de la vitesse de connexion.


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;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>

<div class='examples'>
  <div onClick='mmVcm()'>mergeMap vs concatMap </div>
  <div onClick='smVem()'>switchMap vs exhaustMap</div>
  <div onClick='mmVsm()'>mergeMap vs switchMap </div>
</div>

16voto

Kos Points 425

Dans le diagramme à billes ci-dessous, un flux source qui émet à 5ms , 10ms , 20ms sera *Mappé à un timer(0, 3) , limité à 3 émissions :

mergeMap vs exhaustMap vs switchMap vs concatMap

Jouez avec ce diagramme de billes ici : "mergeMap vs exhaustMap vs switchMap vs concatMap"

Ayant déjà toutes ces réponses géniales, je voulais ajouter une explication plus visuelle.

J'espère que cela aidera quelqu'un

2voto

Picci Points 4743

Au début, c'est un peu long à saisir, du moins pour moi.

Quoi qu'il en soit, considérez ceci :

flatMap EST UN AUTRE NOM POUR mergeMap - mergeMap accepte un paramètre facultatif concurrency qui définit combien d'Observables peuvent être souscrits en même temps.

concatMap est égal à mergeMap avec une concurrence fixée à 1

avec mergeMap vous ne perdez aucun événement émis par les Observables que vous fusionnez comme vous l'avez suggéré dans votre réponse

switchMap fonctionne comme vous l'avez décrit (voir ce bel article pour plus de détails). https://blog.angular-university.io/rxjs-switchmap-operator/ )

1voto

knoefel Points 243

J'ai réalisé une petite démo/exemple pour utiliser les opérateurs demandés il y a quelque temps.

https://stackblitz.com/edit/rxjs-map-operators

Vous pouvez choisir entre un intervalle ou un clic pour l'émission des valeurs observables extérieures. Pour l'observable interne, vous pouvez choisir d'émettre un intervalle (3 éléments) ou une requête http.

Il imprimera les résultats sous la sélection.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X