Skip to content

Comprendre très facilement la différence entre switchMap et mergeMap

Disons le franchement, la différence entre switchMap et mergeMap n'est souvent pas comprise par beaucoup de personnes, même des personnes chevronnées. Plusieurs tutoriels sur le Web ne donnent pas l'explication la plus juste. Ici, on va montrer l'intérêt et l'expliquer simplement

A quoi sert switchMap et mergeMap ?

Les opérateurs SwitchMap et MergeMap sont des outils essentiels pour gérer les observables en Angular, en particulier lorsque vous travaillez avec des effets secondaires ou des observables chaînés.

1. Une analogie simple:

Imaginons que vous écriviez un message texte à plusieurs amis en même temps.

  • switchMap est comme si à chaque fois que vous commencez à écrire à un nouvel ami, vous arrêtez de répondre à l'ami précédent et ne lui envoyez jamais de message.

  • mergeMap, d'autre part, est comme envoyer des messages à plusieurs amis en parallèle sans arrêter la conversation avec l'un d'eux.

2. Comprendre le concept:

Les deux opérateurs permettent principalement de faire du chaînage d'observable. Retenez cette information. Comment faire une suite d'observable sans ces opérateurs ?

Voici la réponse:

ts
import { interval } from 'rxjs'

interval(1000).subscribe((nb1) => {
    console.log('- Premier flux :', nb1)
    interval(1000).subscribe((nb2) => {
        console.log('-- Second flux :', nb2)
    })
})
import { interval } from 'rxjs'

interval(1000).subscribe((nb1) => {
    console.log('- Premier flux :', nb1)
    interval(1000).subscribe((nb2) => {
        console.log('-- Second flux :', nb2)
    })
})

Testez le, vous avez ceci:

terminal
- Premier flux : 0
-- Second flux : 0
- Premier flux : 1
-- Second flux : 1
-- Second flux : 0
- Premier flux : 2
-- Second flux : 2
-- Second flux : 1
-- Second flux : 0
- Premier flux : 3
-- Second flux : 3
-- Second flux : 2
-- Second flux : 1
-- Second flux : 0
- Premier flux : 4
-- Second flux : 4
-- Second flux : 3
-- Second flux : 2
-- Second flux : 1
-- Second flux : 0
- Premier flux : 0
-- Second flux : 0
- Premier flux : 1
-- Second flux : 1
-- Second flux : 0
- Premier flux : 2
-- Second flux : 2
-- Second flux : 1
-- Second flux : 0
- Premier flux : 3
-- Second flux : 3
-- Second flux : 2
-- Second flux : 1
-- Second flux : 0
- Premier flux : 4
-- Second flux : 4
-- Second flux : 3
-- Second flux : 2
-- Second flux : 1
-- Second flux : 0

Le second flux est recréé à chaque seconde, à chaque nouvelle émission du premier flux. Donc, après la première seconde, un second flux est créé. Après la deuxième seconde, un autre second flux est créé en parallèle du premier, et ainsi de suite. Ces multiples flux secondaires émettent leurs valeurs en parallèle et indépendamment les uns des autres. C'est le même comportement de mergeMap: c'est une imbrication d'observables:

ts
import { mergeMap, interval } from 'rxjs'

interval(1000).pipe(
    mergeMap((nb1) => {
        console.log('- Premier flux :', nb1)
        return interval(1000)
    })
).subscribe((nb2) => {
    console.log('-- Second flux :', nb2)
})
import { mergeMap, interval } from 'rxjs'

interval(1000).pipe(
    mergeMap((nb1) => {
        console.log('- Premier flux :', nb1)
        return interval(1000)
    })
).subscribe((nb2) => {
    console.log('-- Second flux :', nb2)
})

Maintenant, quelques fois, nous ne voulons pas avoir ce comportement. Nous souhaitons toujours avoir une imbrication d'observables mais nous ne souhaitons pas que les flux précédents continuent. Nous souhaitons juste passer d'un observable à l'autre. Voici comment le réaliser:

ts
import { interval } from 'rxjs'

let subscription

interval(1000).subscribe((nb1) => {
    console.log('- Premier flux :', nb1)
    if (subscription) subscription.unsubscribe()
    subscription = interval(1000).subscribe((nb2) => {
        console.log('-- Second flux :', nb2)
    })
})
import { interval } from 'rxjs'

let subscription

interval(1000).subscribe((nb1) => {
    console.log('- Premier flux :', nb1)
    if (subscription) subscription.unsubscribe()
    subscription = interval(1000).subscribe((nb2) => {
        console.log('-- Second flux :', nb2)
    })
})

Voici le résultat:

terminal
- Premier flux : 0
-- Second flux : 0
- Premier flux : 1
-- Second flux : 0
- Premier flux : 2
-- Second flux : 0
- Premier flux : 3
-- Second flux : 0
- Premier flux : 4
-- Second flux : 0
- Premier flux : 0
-- Second flux : 0
- Premier flux : 1
-- Second flux : 0
- Premier flux : 2
-- Second flux : 0
- Premier flux : 3
-- Second flux : 0
- Premier flux : 4
-- Second flux : 0

Contrairement au premier exemple, il n'y aura jamais plus d'un "second flux" actif à la fois. À chaque nouvelle émission du premier flux, le second flux précédent est annulé (si existant) avant qu'un nouveau ne soit créé. Cela garantit que les valeurs du second flux sont toujours séquentielles, sans chevauchement avec un précédent second flux. C'est le même comportement de switchMap ! Le code suivant donnera le même résultat:

ts
import { switchMap, interval } from 'rxjs'

interval(1000).pipe(
    switchMap((nb1) => {
        console.log('- Premier flux :', nb1)
        return interval(1000)
    })
).subscribe((nb2) => {
    console.log('-- Second flux :', nb2)
})
import { switchMap, interval } from 'rxjs'

interval(1000).pipe(
    switchMap((nb1) => {
        console.log('- Premier flux :', nb1)
        return interval(1000)
    })
).subscribe((nb2) => {
    console.log('-- Second flux :', nb2)
})

A Retenir

En résumé: switchMap et mergeMap sont des opérateurs qui permettent de faire du chaînage d'observable. La différence est que switchMap annule l'observable imbriqué, tandis que mergeMap ne l'annule pas. C'est tout ! Ne cherchez pas plus loin.😃

3. Exemple pratique:

Supposons que vous ayez une barre de recherche où l'utilisateur peut entrer du texte pour rechercher des articles.

Avec switchMap:

Chaque fois que l'utilisateur saisit un nouveau caractère, une nouvelle requête est déclenchée pour rechercher les articles. Si l'utilisateur tape rapidement "Angular", après avoir tapé "Ang", une requête est envoyée avec "Ang". Mais si la requête pour "Angular" arrive avant celle pour "Ang", switchMap annulera la requête "Ang" et affichera uniquement les résultats pour "Angular".

C'est utile car cela évite d'afficher des résultats périmés.

Avec mergeMap:

Si vous utilisiez mergeMap dans le même scénario, toutes les requêtes seraient exécutées en parallèle. Si la requête pour "Ang" est plus lente que celle pour "Angular", les résultats pour "Angular" pourraient s'afficher en premier, suivis des résultats pour "Ang".