concatWith - Concaténer en Séquence
L'opérateur concatWith combine séquentiellement les autres Observables spécifiés après que l'Observable original soit complete. C'est la version Pipeable Operator de la Creation Function concat.
🔰 Syntaxe de base et utilisation
ts
import { of, delay } from 'rxjs';
import { concatWith } from 'rxjs';
const obs1$ = of('A', 'B').pipe(delay(100));
const obs2$ = of('C', 'D').pipe(delay(100));
const obs3$ = of('E', 'F').pipe(delay(100));
obs1$
.pipe(concatWith(obs2$, obs3$))
.subscribe(console.log);
// Sortie: A → B → C → D → E → Fobs2$commence après la complétion deobs1$, etobs3$commence après la complétion deobs2$.- Peut être utilisé dans une chaîne
.pipe(), facilitant la combinaison avec d'autres opérateurs.
🌐 Documentation officielle RxJS - concatWith
💡 Patterns d'utilisation typiques
- Traitement séquentiel dans un pipeline : Combiner séquentiellement des données supplémentaires à un flux transformé
- Traitement de suivi après complétion : Ajouter un nettoyage ou une notification après le traitement principal
- Chargement progressif de données : Récupérer séquentiellement des données supplémentaires après l'obtention des données initiales
🧠 Exemple de code pratique (avec UI)
Un exemple qui affiche les résultats de recherche principaux, puis affiche séquentiellement les articles recommandés.
ts
import { of, delay } from 'rxjs';
import { concatWith, map } from 'rxjs';
// Création de la zone de sortie
const output = document.createElement('div');
output.innerHTML = '<h3>Exemple pratique de concatWith :</h3>';
document.body.appendChild(output);
// Résultats de recherche principaux
const searchResults$ = of('🔍 Résultat 1', '🔍 Résultat 2', '🔍 Résultat 3').pipe(
delay(500)
);
// Recommandations 1
const recommendations1$ = of('💡 Produit recommandé A', '💡 Produit recommandé B').pipe(
delay(300)
);
// Recommandations 2
const recommendations2$ = of('⭐ Produit populaire X', '⭐ Produit populaire Y').pipe(
delay(300)
);
// Combiner séquentiellement et afficher
searchResults$
.pipe(
concatWith(recommendations1$, recommendations2$),
map((value, index) => `${index + 1}. ${value}`)
)
.subscribe((value) => {
const item = document.createElement('div');
item.textContent = value;
output.appendChild(item);
});- Les résultats de recherche s'affichent d'abord,
- Puis les produits recommandés s'affichent séquentiellement.
- Peut être combiné avec d'autres opérateurs comme
mapdans le pipeline.
🔄 Différence avec la Creation Function concat
Différences de base
concat (Creation Function) | concatWith (Pipeable Operator) | |
|---|---|---|
| Lieu d'utilisation | Utilisé comme fonction indépendante | Utilisé dans la chaîne .pipe() |
| Syntaxe | concat(obs1$, obs2$, obs3$) | obs1$.pipe(concatWith(obs2$, obs3$)) |
| Premier flux | Traité également | Traité comme flux principal |
| Avantage | Simple et lisible | Facile à combiner avec d'autres opérateurs |
Exemples concrets de choix
Pour une simple combinaison, la Creation Function est recommandée
ts
import { concat, of } from 'rxjs';
const part1$ = of('A', 'B');
const part2$ = of('C', 'D');
const part3$ = of('E', 'F');
// Simple et lisible
concat(part1$, part2$, part3$).subscribe(console.log);
// Sortie: A → B → C → D → E → FQuand une transformation est nécessaire en cours de route, le Pipeable Operator est recommandé
ts
import { of } from 'rxjs';
import { concatWith, map, filter } from 'rxjs';
const userData$ = of({ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 });
const additionalData$ = of({ name: 'Charlie', age: 35 });
// ✅ Version Pipeable Operator - complète en un seul pipeline
userData$
.pipe(
filter(user => user.age >= 30), // 30 ans et plus seulement
map(user => user.name), // Extraire le nom uniquement
concatWith(
additionalData$.pipe(map(user => user.name))
)
)
.subscribe(console.log);
// Sortie: Alice → CharliePour ajouter un traitement de suivi au flux principal
ts
import { fromEvent, of } from 'rxjs';
import { concatWith, take, mapTo } from 'rxjs';
// Création du bouton et de la zone de sortie
const button = document.createElement('button');
button.textContent = 'Cliquez 3 fois';
document.body.appendChild(button);
const output = document.createElement('div');
output.style.marginTop = '10px';
document.body.appendChild(output);
const clicks$ = fromEvent(button, 'click');
// ✅ Version Pipeable Operator - naturel comme extension du flux principal
clicks$
.pipe(
take(3), // Obtenir les 3 premiers clics
mapTo('Cliqué'),
concatWith(of('Terminé')) // Message supplémentaire après complétion
)
.subscribe(message => {
const div = document.createElement('div');
div.textContent = message;
output.appendChild(div);
});Résumé
concat: Optimal pour simplement combiner plusieurs fluxconcatWith: Optimal quand vous voulez ajouter des transformations au flux principal et ajouter des suites
⚠️ Points d'attention
Délai dû à l'attente de complétion
L'Observable suivant ne démarre pas tant que l'original n'est pas terminé.
ts
import { interval, of } from 'rxjs';
import { concatWith, take } from 'rxjs';
interval(1000).pipe(
take(3), // Terminer après 3
concatWith(of('Terminé'))
).subscribe(console.log);
// Sortie: 0 → 1 → 2 → TerminéGestion des erreurs
Si une erreur se produit dans l'Observable précédent, les Observables suivants ne sont pas exécutés.
ts
import { throwError, of } from 'rxjs';
import { concatWith, catchError } from 'rxjs';
throwError(() => new Error('Erreur survenue'))
.pipe(
catchError(err => of('Erreur récupérée')),
concatWith(of('Traitement suivant'))
)
.subscribe(console.log);
// Sortie: Erreur récupérée → Traitement suivant