Introduction

Dans le développement d’applications modernes, la gestion de la programmation asynchrone est cruciale. Deux concepts importants émergent souvent : les Promises et les Observables. De plus, l’utilisation de BehaviorSubject pour la gestion des notifications est une pratique courante. Cet article explore ces concepts et leurs différences.

Promises vs Observables

Les Promises

Une Promise représente la valeur éventuelle d’une opération asynchrone. Elle peut être dans l’un des trois états suivants :

  • Pending (en attente)
  • Fulfilled (résolue)
  • Rejected (rejetée)
// Exemple de Promise
const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Données récupérées");
    }, 1000);
  });
};

fetchData().then(data => console.log(data));

Caractéristiques des Promises :

  • ✅ Émettent une seule valeur
  • ✅ Sont “eager” (s’exécutent immédiatement)
  • ✅ Ne peuvent pas être annulées
  • ✅ Gèrent bien les opérations asynchrones simples

Les Observables

Un Observable est un flux de données qui peut émettre plusieurs valeurs au fil du temps. Il fait partie de la bibliothèque RxJS.

// Exemple d'Observable
import { Observable } from 'rxjs';

const dataStream = new Observable(observer => {
  observer.next("Première valeur");
  observer.next("Deuxième valeur");
  
  setTimeout(() => {
    observer.next("Troisième valeur");
    observer.complete();
  }, 1000);
});

dataStream.subscribe(data => console.log(data));

Caractéristiques des Observables :

  • ✅ Peuvent émettre plusieurs valeurs
  • ✅ Sont “lazy” (ne s’exécutent que lors de la souscription)
  • ✅ Peuvent être annulés (unsubscribe)
  • ✅ Offrent de nombreux opérateurs pour la transformation des données
  • ✅ Parfaits pour les flux de données en temps réel

Tableau comparatif

Aspect Promise Observable
Nombre de valeurs Une seule Multiples
Exécution Eager (immédiate) Lazy (à la souscription)
Annulation Impossible Possible (unsubscribe)
Opérateurs Limités (then, catch) Nombreux (map, filter, etc.)
Cas d’usage Requêtes HTTP simples Flux de données, événements

BehaviorSubject pour les notifications

Qu’est-ce qu’un BehaviorSubject ?

Un BehaviorSubject est un type spécial d’Observable qui :

  • Stocke la dernière valeur émise
  • Émet immédiatement cette valeur aux nouveaux souscripteurs
  • Nécessite une valeur initiale

Utilisation pour les notifications

import { BehaviorSubject } from 'rxjs';

// Initialisation avec une valeur par défaut
const notification = new BehaviorSubject<string>('Aucune notification');

Explication de la ligne d’initialisation

notification = new BehaviorSubject<string>('Aucune notification');

Décortiquons cette ligne :

  1. notification : Variable qui stockera notre BehaviorSubject
  2. new BehaviorSubject : Crée une nouvelle instance de BehaviorSubject
  3. <string> : Type TypeScript indiquant que les valeurs émises seront des chaînes
  4. 'Aucune notification' : Valeur initiale obligatoire

Pourquoi utiliser BehaviorSubject pour les notifications ?

class NotificationService {
  private notification = new BehaviorSubject<string>('');
  
  // Observable public pour la souscription
  public notification$ = this.notification.asObservable();
  
  // Méthode pour émettre une nouvelle notification
  showNotification(message: string) {
    this.notification.next(message);
  }
  
  // Méthode pour obtenir la dernière notification
  getCurrentNotification(): string {
    return this.notification.value;
  }
}

Avantages :

  • Persistance : La dernière notification est toujours disponible
  • Réactivité : Tous les composants souscripteurs sont notifiés automatiquement
  • Synchronisation : Les nouveaux composants reçoivent immédiatement l’état actuel
  • Gestion d’état : Parfait pour maintenir l’état global des notifications

Exemple pratique d’utilisation

// Service de notification
@Injectable({
  providedIn: 'root'
})
export class NotificationService {
  private notificationSubject = new BehaviorSubject<{
    message: string;
    type: 'success' | 'error' | 'info';
  }>({ message: '', type: 'info' });
  
  public notification$ = this.notificationSubject.asObservable();
  
  showSuccess(message: string) {
    this.notificationSubject.next({ message, type: 'success' });
  }
  
  showError(message: string) {
    this.notificationSubject.next({ message, type: 'error' });
  }
  
  clearNotification() {
    this.notificationSubject.next({ message: '', type: 'info' });
  }
}

// Composant qui affiche les notifications
@Component({
  selector: 'app-notification',
  template: `
    <div *ngIf="notification.message" 
         [class]="'notification ' + notification.type">
      {{ notification.message }}
    </div>
  `
})
export class NotificationComponent implements OnInit, OnDestroy {
  notification = { message: '', type: 'info' as const };
  private subscription: Subscription;
  
  constructor(private notificationService: NotificationService) {}
  
  ngOnInit() {
    this.subscription = this.notificationService.notification$
      .subscribe(notification => this.notification = notification);
  }
  
  ngOnDestroy() {
    this.subscription?.unsubscribe();
  }
}

Bonnes pratiques

Pour les Promises

  • Utilisez pour les opérations asynchrones simples (requêtes HTTP)
  • Gérez toujours les erreurs avec .catch()
  • Préférez async/await pour une syntaxe plus claire

Pour les Observables

  • Utilisez pour les flux de données complexes
  • N’oubliez jamais de vous désabonner pour éviter les fuites mémoire
  • Utilisez les opérateurs RxJS pour transformer les données

Pour les BehaviorSubject

  • Initialisez toujours avec une valeur par défaut cohérente
  • Encapsulez dans un service pour centraliser la logique
  • Exposez un Observable public plutôt que le BehaviorSubject directement

Conclusion

Le choix entre Promises et Observables dépend du contexte :

  • Promises pour les opérations simples et uniques
  • Observables pour les flux de données complexes
  • BehaviorSubject pour la gestion d’état réactive avec persistance

L’utilisation de notification = new BehaviorSubject() pour les notifications offre une solution élégante pour maintenir et distribuer l’état des notifications dans toute l’application, garantissant que tous les composants restent synchronisés avec les dernières informations.


Cet article fait partie de la série sur la programmation réactive et la gestion d’état en JavaScript/TypeScript.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *