web-dev-qa-db-fra.com

flatMap, mergeMap, switchMap et concatMap dans rxjs?

Quelqu'un, veuillez expliquer la différence entre SwitchMap et FlatMap en termes de Javascript (en perspective angulaire, rxjs 5) 

D'après ce que je comprends.

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

faltMap collecte toutes les observations individuelles et renvoie toutes les observations dans un seul tableau sans se soucier de l'ordre des observations. fonctionne de manière asynchrone.

concatMap conserve l'ordre et émet toutes les valeurs observables, fonctionne de manière synchrone

est-ce correct? 

comment mergeMap fonctionne-t-il différemment des précédents?

quelqu'un, s'il vous plaît expliquer avec un exemple.

6
diEcho

@ZahiC, réponse intéressante - J'aime l'utilisation de la composition fonctionnelle dans l'exemple de code. Si vous me le permettez, j'aimerais l'emprunter pour illustrer quelques points supplémentaires à l'aide d'observables chronométré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 observable outer et inner. La principale différence est la manière dont l'observable extérieur contrôle l'observable intérieur.

Pour les contraster, mon exemple de code les exécute par paires et affiche les valeurs sous la forme [outerValue,innerValue]. J'ai ajouté des intervalles au test et modifié le délai interne afin qu'il y ait un chevauchement temporel (la formule utilisée est delay((5-x)*200)). 


mergeMap vs concatMap

Ces deux sorties toutes les valeurs, la différence est le ordre

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

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

À partir de la sortie, l’émission externe mergeMap peut être retardée dans la séquence, mais concatMap suit une séquence d’émission externe stricte .


switchMap vs exhaustMap

Ces deux étranglement la sortie.

switchMap - Accélération par dernier
[3,0], [4,0], [4,1] 

exhaustMap - Accélérateur par premier
[0,0], [0,1], [4,0], [4,1]

De la sortie, switchMap limite les émissions émises par incomplète interne, mais exhaustMap après émet jusqu'à la fin des précédentes.


mergeMap vs switchMap

J'ai ajouté cela parce que switchmap est souvent utilisé dans les réponses SO dans lesquelles il fallait vraiment utiliser mergeMap. 

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

switchMap - Accélération par dernier
[3,0], [4,0], [4,1] 

Le résultat principal est que la sortie switchMap est imprévisible en fonction du minutage de l'observable interne. Par exemple, si l'intérieur est 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>

4
Richard Matsen

En prenant ceci d'un réponse précédente :

  • flatMap/mergeMap - crée un observable immédiatement pour tout élément source, tous les précédents observables sont conservés.
  • concatMap - attend que l'observable précédent soit terminé avant de créer le suivant
  • switchMap - pour tout élément source, complète l'observable précédent et crée immédiatement le suivant
  • exhaustMap - les éléments source sont ignorés alors que le précédent Observable n'est pas terminé

Voici un exemple du comportement de chacun des opérateurs lorsque la source est un élément immédiat (0,1,2,3,4) et que la fonction de carte 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>

7
ZahiC

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

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

flatMap IS UN AUTRE NOM DE mergeMap - La méthode mergeMap accepte un paramètre facultatif concurrency, qui définit le nombre d'observables pouvant être abonnés simultanément. 

concatMap est égal à mergeMap avec la simultanéité définie sur 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 cet article de Nice pour plus de détails https://blog.angular-university.io/rxjs-switchmap-operator/ )

1
Picci