Background color
Engineering
6
minutes
28 sept. 2023

Angular Signals : cap sur la performance

"Des applications réactives, offrant de meilleures performances", voici la promesse d'Angular Signals. Voyons en quoi cela consiste avec Guillaume !

Guillaume B.
Full Stack Web Developer
Dans cet article

De la bouche des détracteurs d’Angular, il s’agit très certainement de l’un des principaux arguments : la performance.

Indubitablement, à ce petit jeu, ses jeunes compères que sont Vue JS, SolidJS, ou encore Svelte, parviennent à tirer leur épingle du jeu. Heureusement, d’ailleurs, puisque l’existence même de ces frameworks reposent sur les gains offerts ou prétendus, en la matière.

Notons néanmoins que le seul autre framework front-end à fournir une expérience similaire, ainsi qu’un éventail de fonctionnalités aussi large et fourni, un certain React, affiche sensiblement les mêmes résultats.

Bien conscientes du phénomène, les équipes de développement d’Angular se sont penchées sur la question. Avec sa version 16, sortie en mai dernier, des promesses ont donc été faites :

  • d’une expérience de développement accrue.
  • de meilleures performances au run time.
  • d’une réactivité finement modulable (fine-grained reactivity).
  • et d’une meilleure interopérabilité avec RxJS.

Plus qu’une bannière, voici brandi l’étendard : Angular Signals.

ChangeDetection et Zone Js, overkill ?

Avec Angular Signals (actuellement disponible en developer preview), l’axe d’amélioration principal, sur lequel est basé le gain de performances, consiste en un bouleversement total du système de détection de changements. Sans rentrer dans le détail profond des concepts de ChangeDetection et de Zone Js, actuellement en vigueur, il convient néanmoins important d’en rappeler les principaux mécanismes.

C’est à la détection de changement d’Angular que revient la lourde tâche de veiller aux modifications, dans l’application, et de mettre à jour la vue en conséquence. Un enjeu primordial, puisqu’il s’agit d’offrir à l’utilisateur une expérience fluide, et réactive.

De son côté, Zone Js est une bibliothèque qui fournit un mécanisme de conteneur de code Javascript, et permet ainsi de l’exécuter dans un contexte particulier. Dans une application Angular, Zone Js crée une nouvelle zone pour chaque composant.

Détection de changements et Zone Js travaillent donc de pair, afin de suivre les changements au sein de chacune des zones de l’application, à savoir chaque composant, et mettre à jour l’interface utilisateur en conséquence.

Là où le bât blesse, c’est que, dès lors qu’un événement survient, l’intégralité de l’arbre des dépendances est couvert par la détection de changements.

En effet, il s’agit de savoir si les composants enfants, voire parents, sont susceptibles d’être impactés, si leur état affecte la vue. Or, par événement, s’entend _keypress, keydown, click, scroll, retour d’une requête asynchrone, timeout_… et bien d’autres. Il va donc sans dire qu’une telle fonctionnalité a un impact significatif sur les performances de l’application. D’autant que peut se poser la question de sa pertinence : la majorité des composants peut ne pas être affectée par l’événement.

Sur sa documentation officielle, Angular livre sans ambage la portée de son nouvel outil : « optimiser les mises à jour de rendu ». C’est donc tout naturellement que se pose la question : comment ?

Un signal est une valeur avec une sémantique de changement explicite. Dans Angular, un signal est représenté par une fonction getter sans argument renvoyant sa valeur actuelle.

Un type Signal

est en lecture seule. Cela signifie qu'il est possible de propager des valeurs réactives aux consommateurs sans leur donner la capacité de modifier la valeur eux-mêmes. Ce, dans une volonté d’encouragement de bonnes structures architecturales pour le flux de données, dans les applications basées sur les signaux.

Par extension, il existe un type de signal « écrivable ».

Il s’agit d’ailleurs du type renvoyé par la fonction d’instanciation d’un signal. Celui-ci offre également un ensemble de méthodes permettant de mettre à jour la valeur du signal.

Si les exemples ci-dessus se réfèrent à des valeurs primitives, les signaux peuvent contenir n'importe quelle valeur, jusqu’aux structures de données complexes.

Signals, la nouvelle dépendance

Cependant, un signal est bien davantage qu’une valeur qui peut être modifiée, à la volée, via un ensemble de méthodes prédéfinies. Un signal est une valeur réactive, capable d’avertir ses dépendances de son changement. Et c’est bien en cela que réside tout son intérêt.

Est dépendance tout code enregistré pour être informé de la valeur du signal, et souhaite être averti lorsque la valeur du signal change.

En permettant aux diverses parties de l'application de se mettre à jour automatiquement en réponse aux changements de données, cela fait donc des signaux la pierre angulaire de l’application.

Via Signals, il existe plusieurs manières de créer de nouvelles dépendances.

Les signaux calculés tirent leur valeur d’autres signaux. A ce titre, ils sont strictement en lecture seule. Ils sont définis via « computed », et une fonction de dérivation.

La fonction de dérivation de « authorBook » ne s'exécute pas pour calculer sa valeur jusqu'à la première lecture de « authorBook ». Une fois calculée, cette valeur est mise en cache, et les lectures ultérieures renverront la valeur mise en cache sans la recalculer.

Lorsque « book » change, il informe « authorBook » que sa valeur mise en cache n'est plus valide, et la valeur n'est recalculée que lors de la prochaine lecture de « authorBook ». Ainsi l’on s’assure d'effectuer des dérivations coûteuses en termes de calcul dans les signaux calculés, telles que la filtration de tableaux.

De son côté, un effet est une opération avec des effets secondaires qui lit la valeur d’un ou plusieurs signaux, et qui est automatiquement planifiée pour être exécutée chaque fois que la valeur de l’un des signaux change. Les effets s’exécutent toujours au minimum une fois.

Il est intéressant de noter qu’un effet est automatiquement détruit lors de la destruction de son contexte. Cela est évidemment valable pour les composants, mais également pour les services, directives, et autres.

Évidemment, il est possible de créer un signal au sein d’un composant. Mais l’utilisation des signaux n’est pas exclusivement limitée aux composants, et n’importe quel contexte est également propice à l’utilisation des signaux : stores, services, fonctions, modules, etc.

Au service de la performance

Source : Blog Angular

Et voilà que, pour les prochaines versions du framework, l’utilisation de Zone Js deviendra désormais optionnelle. D’autant que les équipes planchent également sur la mise en place de composants basés sur les signaux, qui comprendront un ensemble simplifié de hooks de cycle de vie (Lifecycle Hooks), ainsi qu'une manière plus simple de déclarer les entrées (@Input()) et les sorties (@Output()). Si on ajoute à cela la notion de fine grained reactivity, qui permettra donc de vérifier les changements uniquement dans les composants concernés, on peut clairement s’attendre à des gains significatifs, en termes de performance.

Il ne faut évidemment pas s’attendre, sur ce plan, à ce qu’Angular vienne concurrencer les plus légers des frameworks front-end. La philosophie de l’un n’est pas celle des autres, et Angular a fait le choix d’incorporer de nombreux outils, dans sa version de base (Router, HttpClient, Reactive Forms, BrowserAnimationsModule...). En cela, jamais son bundle ne sera jamais aussi léger que celui d’un Svelte.

Néanmoins, force est de constater que de gros efforts sont consentis, afin d’améliorer la performance des applications construites avec Angular. La sortie de Signals en est la preuve. C’est donc logiquement avec impatience que l’on attend la fin de la preview, et une première version stable : probablement en novembre prochain, avec la sortie de la v.17.0.

Parlons produit

Échangeons sur votre produit

Nous croyons en un nouveau modèle de consulting où l’excellence commence par l’écoute, le partage et une vraie vision

background color