<
Media
>
Article

À la découverte du | async en Angular

7 min
24
/
08
/
2020


Après être intervenu sur un projet reposant sur ngrx, j'ai découvert l'utilisation du <span class="css-span">| async.</span>

Ce <span class="css-span">pipe</span> dit <span class="css-span">impure</span> permet d'alléger grandement la gestion de flux asynchrones et de rendre, à mon sens, beaucoup plus simple la lecture du code et de sa séparation logique.

Nous allons voir ensemble pourquoi ce <span class="css-span">pipe</span> est intéressant.

Utilisation d'un observable dans un composant

Dans notre exemple, nous allons vouloir récupérer une valeur issue d'un observable de deux façons différentes.

  • La première est de <span class="css-span">subscribe l'observable</span> pour ensuite récupérer une valeur.
younupEmployees$.subscribe((employees: Array<YounupEmployee>) => {
   this.employees = employees;
});
<div *ngFor="let employee of employees”>
     <span>{{ employee.firstName }}</span>
     <span>{{ employee.lastName }}</span>
</div>
  • La seconde est de pouvoir <span class="css-span">subscribe</span> à un <span class="css-span">observable</span> directement dans la vue
<div *ngFor="let employee of younupEmployees$ | async”>
     <span>{{ employee.firstName }}</span>
     <span>{{ employee.lastName }}</span>
</div>

Les deux façons de faire peuvent paraître semblables et pourtant, elles ne le sont pas.

En quoi sont-elles différentes ?

Gestion de l'<span class="css-span">observable</span> dans le composant

Quand vous faites un subscribe dans un composant pour récupérer une valeur, vous pouvez rendre accessible celle-ci dans l'ensemble de votre composant.

L'état de la variable est conservé dans celui-ci.

Si on s'amuse à utiliser la variable dans la vue, le <span class="css-span">binding</span> se fera de façon automatique.

Mais quelle est le coût de cette "liberté" ?

Si par hasard vous faites les choses biens et que vous pensez à vos performances applicatives, vous allez vouloir faire en sorte que votre composant soit en <span class="css-span">OnPush Change Detection</span>.

Pour rappel, en <span class="css-span">OnPush</span>, le composant effectuera son <span class="css-span">rendering</span> dans les cas suivants :
  • les références des <span class="css-span">Inputs</span> changent ;
  • lors d'un événement provenant du composant ou de ses enfants ;
  • si vous lancez la détection de changement manuellement.
Dans le cas contraire, c'est la stratégie par Default qui est appliquée.

Donc si l'on subscribe et que l'on attend une quelconque réactivité de la variable dans le template, nous serons obligés de le signaler à Angular. Il faut également penser à <span class="css-span">unsubscribe</span> de votre observable, sous peine d'avoir un très belle fuite mémoire silencieuse.

Laissons le template travailler pour nous

En ce qui concerne le <span class="css-span">| async</span>, c'est dans le template que notre observable est géré. Le framework se charge de <span class="css-span">subscribe</span> et d'<span class="css-span">unsubscribe</span> pour nous !

Si notre composant est un mode <span class="css-span">OnPush</span>, la réactivité se fera dans le template également.

<div>{{ (younupInfo$ | async)?.babyfootName }}</div>
<div>{{ (younupInfo$ | async)?.babyfootColor }}</div>

Grace à cet exemple, nous voyons immédiatement l'inconvénient de cette façon de faire. Nous devons multiplier les <span class="css-span">| async</span> pour pouvoir accéder à nos différentes valeurs, et cela veut dire que l'on multiplie les <span class="css-span">subscribe</span> sur un même observable...

<ng-container *ngIf="younupBabyfoot$ | async as younupBabyfoot">
     <div>{{ younupBabyfoot.name }}</div>
     <div>{{ younupBabyfoot.color }}</div>
</ng-container>

En utilisant un alias, le <span class="css-span">pipe</span> n'est utilisé qu'une seule fois grâce au <span class="css-span">ngIf</span>.

Que se passe t'il avec plusieurs <span class="css-span">observables</span> ?

<ng-container *ngIf="younupBabyfoot$ | async as younupBabyfoot">
     <div>{{ younupBabyfoot.name }}</div>
     <div>{{ younupBabyfoot.color }}</div>
</ng-container>

<ng-container *ngIf="younupFlipper$ | async as younupFlipper">
     <div>{{ younupFlipper.name }}</div>
     <div>{{ younupFlipper.color }}</div>
</ng-container>

Le système est le même mais nous ne pouvons pas regrouper les informations.

Dans notre cas, impossible de faire cohabiter les informations de <span class="css-span">younupBabyfoot</span> et <span class="css-span">younupFlipper</span> au même niveau, leur portée n'est qu'au <span class="css-span">ngIf</span> où ils sont définis.

<ng-container  
     *ngIf="{   
     babyfoot: younupbabyfoot$ | async,
     flipper: younupFlipper$ | async
   } as younup"
>

     <div>{{ younup.babyfoot.name }}</div>
     <div>{{ younup.babyfoot.color }}</div>
     <div>{{ younup.flipper.name }}</div>
     <div>{{ younup.flipper.color }}</div>
</ng-container>

En englobant les <span class="css-span">| async</span> dans un objet, on s'assure que le <span class="css-span">ngIf</span> ne sert qu'a la définition de l'alias, la portée n'est plus un problème.

Conclusion

Après avoir uniquement utilisé <span class="css-span">subscribe</span>, je suis convaincu par cette nouvelle approche. Comme nous l'avons vu plus haut, les inconvénients peuvent être compensés avec des alias dans le template et nous pouvons faire grossir cette gestion en englobant dans un objet qui regroupe les <span class="css-span">| async</span>.

N'hésitez pas à l'essayer pour faire votre propre idée !

No items found.
ça t’a plu ?
Partage ce contenu
Benjamin

Benjamin, expert front Younup, aime le code smart, compréhensible et réutilisable. Malgré ses différentes tentatives de supprimer ES4 et Angular3 il a échoué, damn !

Ses technos de prédilection sont le Typescript, il adore transpiler en ES3 pour Internet Explorer, mais aussi le JavaScript. Hé oui, on peut tout faire avec (enfin aussi n’importe quoi…). Avouons-le, il a aussi un petit crush pour les PWA. Quand le web vient titiller le monde des apps natives et apporter une concurrence ultra positive !

Et si vous ne trouvez pas Benjamin derrière son écran se tirant les cheveux pour avoir oublié un CTRL+S, il devrait être sur un terrain, non loin du Saint Laurent, à travailler ses shoots…