Gestion de la Subscription ⚠️
Dans les exemples ci-dessus, l'objet Subscription
retourné par la méthode subscribe
est simplement ignoré.
Il faut s'assurer que le composant unsubscribe
de l'Observable
avant sa destruction (et également si une nouvelle requête est déclenchée par exemple en cas de "refresh").
Dans le cas d'Observable
s infinis cela évite des fuites mémoire et surconsommation CPU.
Dans notre cas, cela évite la congestion des requêtes HTTP (dans le cas où le composant est détruit et reconstruit plusieurs fois rapidement par exemple ou encore lors de la navigation sur l'application via le Routing).
Unsubscribe
dans ngOnDestroy
Unsubscribe
dans ngOnDestroy
On profite généralement du "Lifecycle Hook" ngOnDestroy
pour déclencher l'unsubscribe
.
Et par précaution dans le cas où la subscription
est créé plus tard.
L'inconvénient de cette approche est sa verbosité. Elle en devient "error-prone".
Unsubscribe
avec l'opérateur takeUntil
Unsubscribe
avec l'opérateur takeUntil
Il existe une approche similaire avec l'opérateur takeWhile
qui se base sur un valeur "boolean" plutôt qu'un Observable
mais il est préférable de l'éviter.
Contrairement à l'approche takeUntil
, takeWhile
ne peut pas détecter en temps réel le changement de la variable "boolean" et la requête HTTP ne sera donc pas interrompue.
Exemple
https://github.com/wishtack/wishtack-book-shop/tree/7-unsubscribe-using-take-until
Unsubscribe avec le Pipe async
async
Dans les cas les plus simples, cette approche est la plus adaptée car c'est la moins verbeuse est la plus réactive.
Le "pipe" async
permet de préparer l'Observable dans le composant
et laisser la vue subscribe
quand elle en a besoin et si elle en a besoin.
Remarquez que l'on se permet de créer l'Observable
directement dans le constructeur. En effet, tant que l'on ne subscribe
pas, aucun traitement n'est déclenché.
A éviter
Il est possible d'utiliser la syntaxe perturbante ci-dessous mais il est préférable de l'éviter.
Fonctionnement du "pipe" async
async
Le "pipe" async
subscribe
à l'Observable
bookList$
et permet de mettre à jour la vue en conséquence.
A la destruction de l'élément (e.g. : "toggle" de la liste via *ngIf
), le "pipe" async
unsubscribe
automagiquement.
Gotcha
En essayant d'afficher le nombre de "book" en créant un autre Observable
:
Cela "fonctionne" mais on peut remarquer que la requête HTTP a été exécutée deux fois.
L'Observable
créé par le service HttpClient
est de type "Cold" (c'est à dire Lazy).
Chaque "pipe" async
appelle la méthode subscribe
et déclenche donc la requête HTTP puis les traitements appliqués par les opérateurs (l'opérateur map
dans notre cas).
shareReplay
shareReplay
Le comportement souhaité est le suivant :
Tant qu'il n'y a aucun appel à
subscribe
(explicite ou implicite viaasync
), le traitement ne doit pas s'exécuter.Au premier
subscribe
, le traitement doit être déclenché.Les
subscribe
s supplémentaires ne doivent pas redéclencher le traitement mais simplement attendre le résultat.Les souscripteurs qui arrivent après la récupération du résultat doivent récupérer la dernière valeur obtenue.
L'intégralité de se traitement se fait simplement avec l'opérateur shareReplay
en lui indiquant en paramètre la taille du buffer de mémorisation. Un buffer de taille 1 va mémoriser la dernière valeur.
Le problème décrit au paragraphe précédent est alors résolu ainsi :
Gestion d'erreurs
Pour capturer les erreurs et détecter la fin du traitement (i.e. try
/ catch
/ finally
), il suffit d'utiliser les opérateurs catchError
et finalize
.
EMPTY
est une constante contenant un Observable
vide. Vous êtes libres de retourner un Observable
contenant des données (de secours) provenant d'une autre source (cache etc...).
Exemple
https://github.com/wishtack/wishtack-book-shop/tree/8-unsubscribe-using-async-pipe
Pour reproduire l'erreur ci-dessus, vous pouvez bloquer le domaine de l'API sur Chrome via le menu décrit ci-dessous.
RxScavenger
https://blog.wishtack.com/2018/05/30/handle-rxjs-subscriptions-properly-using-rx-scavenger/
Dernière mise à jour