Conseils pour optimiser votre application angulaire
Découvrez ces astuces et techniques que vous pouvez utiliser pour optimiser des applications angulaires. Apprenez à utiliser le chargement paresseux, le rendu côté serveur, etc.
Lorsqu'une application passe de quelques lignes de code à plusieurs fichiers ou dossiers de code, alors chaque octet ou seconde enregistré a son importance. Lorsqu'une application atteint cette taille, le mot «optimisation» est souvent chuchoté. En effet, une application de cette taille fonctionnerait généralement comme un train fonctionnant au charbon, mais les utilisateurs s’attendent à un train à grande vitesse.
Nous examinerons aujourd’hui quelques techniques utiles à adopter lors de la tentative d’optimisation des applications angulaires. Ces techniques sont utiles pour améliorer les performances de temps de chargement et d'exécution.
Chargement paresseux
Technique très utile et l'une des plus recommandée pour la majorité des applications Web, le chargement paresseux est essentiellement un chargement à la demande. Dans cette technique, certaines parties de votre application sont regroupées séparément du regroupement principal, ce qui signifie qu'elles se chargent lorsqu'une action est déclenchée. Par exemple, vous avez un composant appelé AboutComponent
. Ce composant affiche la page À propos de. Cette page n’est pas la première chose que l’utilisateur voit lors du chargement de la page. Ainsi, le AboutComponent
peut être groupé séparément et chargé uniquement lorsque l'utilisateur tente d'accéder à la page A propos.
Pour obtenir un chargement paresseux dans Angular, des modules paresseux sont utilisés, ce qui signifie que vous pouvez définir des modules séparément. le fichier de module principal de l'application. Angular construit naturellement un paquet séparé pour chaque module différé. Nous pouvons donc lui demander de ne charger le module que lorsque l'itinéraire est demandé. Cette technique améliore les performances de temps de chargement mais affecte les performances d'exécution en ce sens que le chargement des modules différés peut prendre un certain temps en fonction de la taille du module. C'est pourquoi Angular dispose d'une stratégie utile appelée PreloadingStrategy . 19659003] PreloadingStrategy
est utilisé pour dire au RouterModule
comment charger un module différé, et l'une des stratégies est PreloadAllModules
. Ceci charge tous les modules différés en arrière-plan après le chargement de la page pour permettre une navigation rapide vers le module lazied.
Voyons un exemple:
Vous avez un module de fonction appelé FoodModule
à charger paresseux. . Le module comporte un composant appelé FoodTreeComponent
et un module de routage FoodRoutingModule
.
import { NgModule ] de de . angular / core ';
import { CommonModule } de ' @ angular / common ';
import { FoodRoutingModule } de './ food-routing.module' ;
import { FoodTreeComponent } de './food-tree/food-tree.component';
@ NgModule ( {
importations : [
Module commun
FoodRoutingModule
]
declarations : [ FoodTreeComponent ]
} )
export classe FoodModule { ]. chargez le composant FoodModule
avec la stratégie PreloadAllModules
enregistrez le module de fonction en tant que route et incluez la stratégie de chargement:
import { NgModule ] de '@ angular / core' ;
import { FormsModule } de '@ angular / forms' ;
import { BrowserModule } de '@ angular / platform-browser' ;
import { de PreloadAllModules . , RouterModule } de '@ angular / router' ;
import { AppComponent } de ' ./app.component';
@ NgModule ( {
déclarations : [
AppComponent
]
importations : [
NavigateurModule
FormulairesModule
RouterModule . forRoot ( [
{
chemin : 'nourriture'
loadChildren : './ food / food.module # FoodModule'
}
] { preloadStrategy : PreloadAllModules } )
]
fournisseurs : []
bootstrap : [ AppComponent ]
}
classe d'exportation de classe AppModule { ] de . Stratégie
Dans votre application, Angular exécute des vérifications pour déterminer si elle doit mettre à jour l'état d'un composant. Ces vérifications, appelées détection de modification, sont exécutées lorsqu'un événement est déclenché ( onClick
onSubmit
), lorsqu'une demande AJAX est faite et après plusieurs autres opérations asynchrones. Chaque composant créé dans une application angulaire est associé à un détecteur de changement lors de l'exécution de l'application. Le travail du détecteur de changement consiste à restituer le composant lorsqu'une valeur change dans le composant.
Tout va bien lorsque vous travaillez avec une petite application - la quantité de restitutions importera peu - mais dans une application beaucoup plus grande. , plusieurs re-rendus affecteront les performances. En raison du flux de données unidirectionnel d'Angular, lorsqu'un événement est déclenché, les mises à jour de chaque composant sont vérifiées, et lorsqu'une modification est trouvée dans un composant, son détecteur de modification associé s'exécute pour restituer le rendu du composant. [19659003] Maintenant, cette stratégie de détection de changement peut bien fonctionner, mais elle ne sera pas évolutive, tout simplement parce que cette stratégie devra être contrôlée pour fonctionner efficacement. Angular, dans toute sa grandeur, offre un moyen de gérer la détection du changement de manière plus intelligente. Pour ce faire, vous devez adopter des objets immuables et utiliser la stratégie de détection de changement onPush
.
Voyons un exemple:
Vous avez un composant nommé BankUser
. Ce composant prend un objet Input
objet
contenant le nom de
et d'un utilisateur de banque:
@ . Composant ( {
sélecteur : 'utilisateur de banque'
modèle :
{{user.name}}
{{user.email}}
`
} )
classe BankUser {
@ Input () utilisateur ;
}
Ce composant est à présent restitué par un composant parent de la banque
qui met à jour le nom. de l'utilisateur sur le clic d'un bouton:
@ Component ( {
sélecteur : 'the-bank'
modèle :
`
} )
classe Banque {
bankUser = {
nom : 'Mike Richards'
email : 'mike@richards.com'
}
updateName () {
ceci . . bankUser . name = 'John Peters'
}
}
Au clic de ce bouton, Angular lancera le cycle de détection des modifications pour mettre à jour le nom de la propriété. du composant. Ceci n’est pas très performant, nous devons donc demander à Angular de mettre à jour le composant BankUser
uniquement si l’une des conditions suivantes est remplie:
- La détection des modifications s’effectue manuellement en appelant
detectChanges
- . ] Le composant ou ses enfants ont déclenché un événement
- La référence de l'entrée
a été mise à jour
. Le composant BankUser
est explicitement mis à jour. Mettons à jour le composant BankUser
pour appliquer ces conditions en ajoutant une propriété changeDetection
lors de la définition du composant:
@ Component ( {
sélecteur : 'utilisateur de banque'
modèle :
{{user.name}}
{{user.email}}
`
changeDetection : ChangeDetectionStrategy . OnPush
} )
classe d'exportation BankUser {
@ Input () utilisateur ;
}
Après avoir effectué cette mise à jour, un clic sur le bouton Update Name
n'aura aucun effet sur le bouton. composant sauf si nous modifions également le format de mise à jour du nom de l'utilisateur de la banque
. Mettez à jour la méthode updateName
pour qu'elle ressemble à l'extrait ci-dessous:
updateName () {
this . bankUser . ] = {
... ceci . bankUser
nom : 'John Peters'
} ;
}
Cliquez sur le bouton pour activer l'une des conditions définies: l'entrée
. La référence a été mise à jour et est différente de la précédente.
TrackBy
Le rendu des listes peut affecter les performances d'une application - d'énormes listes avec des écouteurs attachés peuvent provoquer un scroll jank, ce qui signifie que votre application balbutie lorsque les utilisateurs font défiler un liste énorme. Un autre problème avec les listes est leur mise à jour: l'ajout ou la suppression d'un élément d'une longue liste peut entraîner de graves problèmes de performances dans les applications Angular si nous n'avons pas fourni à Angular le moyen de suivre chaque élément de la liste.
Voici une liste de fruits contenant 1 000 noms de fruits affichés dans votre application. Si vous souhaitez ajouter un autre élément à cette liste, Angular doit recréer le nœud DOM complet pour ces éléments et les restituer. Cela correspond à 1 001 nœuds DOM créés et rendus lorsqu'un seul élément est ajouté à la liste. La situation s’aggrave si la liste atteint 10 000 éléments ou plus.
Pour aider Angular à gérer correctement la liste, nous allons fournir une référence unique pour chaque élément de la liste à l’aide de la fonction trackBy
. Prenons un exemple: Une liste d’éléments rendus dans un composant appelé FruitsComponent
. Voyons ce qui se passe dans le DOM lorsque nous essayons d’ajouter un élément supplémentaire avec et sans la fonction trackBy
.
@ Component ( {
sélecteur : 'the-fruits'
modèle :
- {{fruit.name}}
`
} )
classe d'exportation FruitsComponent {
fruits = [
{
id : 1
nom : 'Banane'
}
{
id : 2
nom : 'Pomme'
}
{
id : 3
nom : 'Ananas'
}
{
id : 4
nom : 'Mangue'
}
] ;
addFruit () {
cette . . fruits = [
... ceci . fruits
{
id : 5
nom : 'Pêche'
}
] ;
}
}
Sans fournir de référence unique avec traceBy
les éléments Le rendu de la liste des fruits est supprimé, recréé et rendu en un clic sur le bouton Ajouter un fruit
. Nous pouvons rendre cela plus performant en incluant la fonction trackBy
.
Mettez à jour la liste rendue pour utiliser une fonction trackBy
et le composant pour inclure une méthode renvoyant le . id
de chaque fruit.
@ Composant ( {
...
modèle :
- {{fruit.name}}
`
} )
classe d'exportation FruitsComponent {
fruits = [
...
] ;
...
trackUsingId ( index fruit ) {
return fruit . id ;
}
}
Après cette mise à jour, Angular sait ajouter le nouveau fruit à la fin de la liste sans recréer le reste de la liste.
Rendu côté serveur
Maintenant, nous savons qu'un chargement paresseux de votre application vous fera gagner un temps considérable sur la page en raison de la taille réduite du paquet et du chargement à la demande. De plus, le rendu côté serveur peut considérablement améliorer le temps de chargement de la page initiale de votre application.
Normalement, Angular exécute votre application directement dans le navigateur et met à jour le DOM lorsque des événements sont déclenchés. Mais en utilisant Angular Universal, votre application sera générée sous forme d'application statique sur votre serveur et servie à la demande du navigateur, ce qui réduira considérablement les temps de chargement. Les pages de votre application peuvent également être pré-générées sous forme de fichiers HTML.
Les performances de référencement constituent un autre avantage du rendu côté serveur: puisque votre application sera rendue sous forme de fichiers HTML, les robots d'exploration de Web peuvent facilement utiliser les informations de la page Web.
Le rendu côté serveur prend en charge la navigation vers d'autres itinéraires à l'aide de routerLink [
mais n'a pas encore pris en charge les événements. Cette technique est donc utile lorsque vous souhaitez servir certaines parties de l'application à des heures record avant de naviguer vers l'application complète. Consultez ce didacticiel approfondi de l'équipe Angular pour apprendre à utiliser le rendu côté serveur à l'aide d'Angular Universal.
Détection des modifications de poignées
Vous pouvez trouver des exemples de composants dans votre arborescence de composants. re-rend plusieurs fois dans un court laps de temps en raison d'effets secondaires. Cela n’aide pas la cause très performante à laquelle nous travaillons. Dans des situations comme celle-ci, vous devez intervenir et vous salir les mains: vous devez empêcher le rendu de votre composant.
Supposons qu'un composant dont la propriété est connectée à un observateur et que la valeur de cet observateur change très souvent - peut-être est-ce une liste d'éléments que différents utilisateurs de l'application ajoutent. Plutôt que de laisser le composant refaire le rendu à chaque fois qu'un nouvel élément est ajouté, nous attendons de gérer la mise à jour de l'application toutes les six secondes.
Regardez l'exemple ci-dessous:
Dans ce composant, nous avons une liste. de fruits, et un nouveau fruit est ajouté toutes les trois secondes:
@ Component ( {
sélecteur : 'app-root'
modèle :
-
{{fruit.name}}
`
styleUrls : [ './ app.component.scss' ]
} )
classe d'exportation AppComponent 19659304] constructeur () {
setInterval ( () => {
ceci . ] addFruit () ;
} 2000 ) ;
}
fruits = [
{
id : 1
nom : 'Banane'
}
{
id : 2
nom : 'Pomme'
}
{
id : 3
nom : 'Ananas'
}
{
id : 4
nom : 'Mangue'
}
] ;
addFruit () {
cette . . fruits = [
... ceci . fruits
{
id : 5
nom : 'Pêche'
}
] ;
}
trackUsingId ( index fruit ) {
return fruit . id ;
}
}
Imaginez maintenant si ce composant rendait d'autres composants qui rendaient d'autres composants. Je suis sûr que vous obtenez l’image que je suis en train de peindre. Ce composant sera généralement mis à jour 20 fois par minute, ce qui donnera beaucoup de relectures en une minute. Ce que nous pouvons faire ici est de détacher le composant du détecteur de changement qui lui est associé et de gérer nous-mêmes la détection de changement.
Ce composant étant mis à jour 20 fois par minute, nous souhaitons le diviser par deux. Nous demanderons au composant de vérifier les mises à jour toutes les six secondes à l'aide du composant ChangeDetectorRef
.
Le jour, mettons à jour ce composant pour utiliser cette mise à jour:
@ Component [[19659014] {
sélecteur : 'app-root'
modèle : ...
} )
classe d'exportation le composant AppComponent implémente OnInit de InApp [1965904]. {
constructeur ( détective privé : ChangeDetectorRef ) {
...
}
fruits = [
...
] ;
...
ngAfterViewInit () {
ceci [19659014]. détecteur . détachez () ;
}
ngOnInit () [ setInterval ( () => {
ceci . détecteur . détectez les échanges () ;
} 6000 ) ;
}
}
Ce que nous avons fait maintenant est de détacher le ChangeDetector
après le rendu de la vue initiale. Nous nous détachons dans le cycle de vie AfterViewInit
plutôt que dans le cycle de vie OnInit
car nous souhaitons que le tableau ChangeDetector
rende l'état initial du fruit fruits
avant. on le détache. Dans le cycle de vie OnInit
nous gérons nous-mêmes la détection des changements en appelant la méthode detectChanges
toutes les six secondes. Nous pouvons maintenant mettre à jour le composant par lots, ce qui améliorera radicalement les performances d'exécution de votre application.
Options supplémentaires à explorer
Nous avons étudié quelques moyens d'optimiser une application angulaire. Quelques autres techniques notables sont:
- Compression d'images et chargement paresseux d'éléments d'image : La compression d'images est utile pour réduire la taille des images tout en préservant la qualité. Vous pouvez utiliser des services de compression d'images tels que ShortPixel Kraken et TinyPNG . Vous pouvez également utiliser la technique de chargement paresseux d'images hors écran en utilisant des API telles que IntersectionObserver ou une bibliothèque telle que ng-lazyload-image .
- Activer prodMode : lors de la création de votre application pour la production, vous pouvez utiliser
enableProdMode
pour optimiser votre génération pour la production.
- Travailleurs de service: Les travailleurs de service peuvent être utilisés pour précharger votre application et les servir à partir du cache, ce qui active les fonctionnalités hors ligne et réduit le temps de chargement des pages. Vous pouvez activer la fonctionnalité Service worker pour votre application Angular en suivant ce guide .
Conclusion
L'utilisation de techniques d'optimisation utiles, si minimes soient-elles, les résultats peuvent sembler hors de propos pourrait beaucoup contribuer à rendre votre application encore plus fluide qu'elle ne l'est actuellement. La CLI d’Angular pour amorcer votre application a utilisé plusieurs techniques d’optimisation. Assurez-vous de commencer à utiliser la CLI. Une optimisation accrue de votre serveur produira de meilleurs résultats. Veillez donc à vous méfier de ces techniques. Vous pouvez inclure des techniques utiles qui fonctionnent également pour votre application. Happy coding.
Pour plus d’informations sur la création d’applications avec Angular:
Consultez notre page All Things Angular qui contient un large éventail d’informations et de pointeurs d’informations angulaires, allant de sujets brûlants à la hausse. informations à jour pour savoir comment démarrer et créer une interface utilisateur convaincante.
Les commentaires sont désactivés en mode Aperçu.
Source link