Promises vs Observables : guide complet, différences et usages en JavaScript
Promises vs Observables : la question revient sans cesse chez les développeurs JavaScript et TypeScript. Mais quelles sont les différences entre ces deux approches de la programmation asynchrone ? Faut-il privilégier l’une ou l’autre selon le contexte ? Pour vous aider à y voir plus clair, ce guide complet vous explique tout, avec des exemples concrets, un tableau comparatif, des images explicatives et des conseils pour bien choisir selon vos besoins.
Différences entre Promises et Observables
Fonctionnement des Promises en JavaScript
Une Promise représente la valeur éventuelle d’une opération asynchrone. Concrètement, 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
Observables et flux de données avec RxJS
Un Observable est un flux de données qui peut émettre plusieurs valeurs au fil du temps. Par ailleurs, 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 : Promises, Observables et flux asynchrones
| 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 et gestion d’état réactive
Présentation du BehaviorSubject
Un BehaviorSubject est un type spécial d’Observable qui présente plusieurs particularités :
- Il stocke la dernière valeur émise
- Il émet immédiatement cette valeur aux nouveaux souscripteurs
- Il nécessite une valeur initiale
Exemple d’utilisation de BehaviorSubject pour les notifications
import { BehaviorSubject } from 'rxjs';
// Initialisation avec une valeur par défaut
const notification = new BehaviorSubject<string>('Aucune notification');
Détail de l’initialisation d’un BehaviorSubject
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
Avantages de BehaviorSubject pour la gestion des 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
Cas pratique : notifications réactives avec BehaviorSubject
// 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 la programmation asynchrone en JavaScript
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 : Promises, Observables ou BehaviorSubject ?
Le choix entre Promises et Observables dépend du contexte. Ainsi :
- 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.
Pour aller plus loin : Programmation réactive et gestion d’état en JavaScript
Ressources externes utiles :


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