Skip to content

exhaustAll - Ignorer les nouveaux Observables internes pendant l'exécution

L'opérateur exhaustAll reçoit un Higher-order Observable (Observable d'Observables) et ignore les nouveaux Observables internes si un est en cours d'exécution.

Syntaxe de base et utilisation

ts
import { fromEvent, interval } from 'rxjs';
import { map, exhaustAll, take } from 'rxjs';

const clicks$ = fromEvent(document, 'click');

// Démarre un nouveau compteur à chaque clic (Higher-order Observable)
const higherOrder$ = clicks$.pipe(
  map(() => interval(1000).pipe(take(3)))
);

// Ignore les nouveaux clics si un compteur est en cours d'exécution
higherOrder$
  .pipe(exhaustAll())
  .subscribe(x => console.log(x));

// Sortie (avec 3 clics consécutifs):
// 0 (1er compteur)
// 1 (1er compteur)
// ← clic ici (ignoré: 1er en cours)
// 2 (1er compteur) ← complété
// ← clic ici (accepté: pas de compteur en cours)
// 0 (2ème compteur)
// 1 (2ème compteur)
// 2 (2ème compteur)
  • Si un Observable interne est en cours d'exécution, les nouveaux Observables internes sont ignorés
  • Attend la complétion de l'Observable en cours avant d'accepter le suivant
  • Idéal pour prévenir les exécutions doubles

Documentation officielle RxJS - exhaustAll

Patterns d'utilisation typiques

  • Prévention du double-clic (prévention des clics répétés sur un bouton)
  • Prévention de la double soumission de requêtes de connexion
  • Prévention de l'exécution en double des opérations de sauvegarde

Exemple de code pratique

Un exemple qui empêche le double-clic sur un bouton de sauvegarde

ts
import { fromEvent, of } from 'rxjs';
import { map, exhaustAll, delay } from 'rxjs';

const saveButton = document.createElement('button');
saveButton.textContent = 'Sauvegarder';
document.body.appendChild(saveButton);

const output = document.createElement('div');
document.body.appendChild(output);

let saveCount = 0;

// Événement de clic du bouton
const clicks$ = fromEvent(saveButton, 'click');

// Higher-order Observable: traitement de sauvegarde simulé pour chaque clic
const saves$ = clicks$.pipe(
  map(() => {
    const id = ++saveCount;
    const start = Date.now();

    // Désactive temporairement le bouton (feedback visuel)
    saveButton.disabled = true;

    // Traitement de sauvegarde simulé (délai de 2 secondes)
    return of(`Sauvegarde terminée #${id}`).pipe(
      delay(2000),
      map(msg => {
        saveButton.disabled = false;
        const elapsed = ((Date.now() - start) / 1000).toFixed(1);
        return `${msg} (${elapsed}s)`;
      })
    );
  }),
  exhaustAll() // Ignore les nouveaux clics pendant la sauvegarde
);

saves$.subscribe(result => {
  const item = document.createElement('div');
  item.textContent = result;
  output.prepend(item);
});

// Log des clics ignorés
clicks$.subscribe(() => {
  if (saveButton.disabled) {
    console.log('Clic ignoré car sauvegarde en cours');
  }
});
  • Pendant le traitement de sauvegarde, les nouveaux clics sont ignorés
  • Après la complétion de la sauvegarde, le prochain clic est accepté

Opérateurs associés

OpérateurDescription
exhaustMapRaccourci pour map + exhaustAll (couramment utilisé)
mergeAllSouscrit à tous les Observables internes en parallèle
concatAllSouscrit aux Observables internes séquentiellement (les met en file d'attente)
switchAllBascule vers le nouvel Observable interne (annule l'ancien)

Comparaison avec d'autres opérateurs

OpérateurQuand un nouvel Observable interne est émis
mergeAllExécution en parallèle
concatAllAjout à la file d'attente (attend la complétion du précédent)
switchAllAnnule l'ancien et bascule
exhaustAllIgnore (attend la complétion de l'actuel)

Points d'attention

Perte d'événements

exhaustAll ignore complètement les événements pendant l'exécution, donc c'est inapproprié si vous voulez traiter tous les événements.

ts
// ❌ Si vous voulez enregistrer tous les clics, exhaustAll est inapproprié
// ✅ Utilisez mergeAll ou concatAll

Feedback UI

Il est important de communiquer visuellement à l'utilisateur que "l'événement a été ignoré".

ts
// Désactive le bouton
saveButton.disabled = true;

// Affiche un message toast
showToast('Traitement en cours. Veuillez patienter.');

Cas d'utilisation appropriés

exhaustAll est optimal pour

  • Traitement de connexion (prévention de la double soumission)
  • Traitement de sauvegarde (prévention de l'exécution en double)
  • Animation (ne pas démarrer une nouvelle animation pendant l'exécution)

exhaustAll est inapproprié pour

  • Traitement de recherche (vous voulez exécuter la dernière recherche → switchAll)
  • Traitement de tous les événements (→ mergeAll ou concatAll)

Publié sous licence CC-BY-4.0.