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 :
notification
: Variable qui stockera notre BehaviorSubjectnew BehaviorSubject
: Crée une nouvelle instance de BehaviorSubject<string>
: Type TypeScript indiquant que les valeurs émises seront des chaînes'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.