web-dev-qa-db-fra.com

Angular JS Scaling & Performance

Nous nous battons la tête contre les problèmes de performance avec une application Angular que nous construisons pour une banque.

Malheureusement, c'est une rupture de contrat de montrer des extraits du code. Quoi qu'il en soit, je peux décrire certains des principaux problèmes en cours et j'espère que les meilleures pratiques pourront être recommandées.

Structure des applications:

  • Essentiellement, une page géante multi-formulaire.
  • Chaque forme est son propre partiel, avec des contrôleurs et partiels imbriqués d'environ 3 niveaux de profondeur.
  • Les mêmes formes sont répétées sur une collection d'objets json.
  • Chaque formulaire est lié à l'objet/modèle sur lequel il est répété.
  • Nous sommes censés prendre en charge de 1 à 200 formulaires sur la page.

Si vous regardez la chronologie. Nous passons beaucoup de temps dans la méthode jQuery parse html, la méthode jQuery recalculate stye, le GC Event (Garbage Collection). J'imagine que les minimiser devrait accélérer un peu les choses. Ils font tous partie du cycle de vie Angular, mais il peut y avoir de meilleures façons de les éviter. Voici quelques captures d'écran du profileur:

Recalculate StyleGC Event

En fin de compte, l'application est lente car le nombre de formulaires répétés dépasse 5. Chaque formulaire est relativement indépendant des autres. Nous avons essayé de ne regarder aucune propriété partagée entre les formulaires.

42
trevorewen

Vous devez créer des directives personnalisées afin de limiter les problèmes de performances avec angular. Contrairement à ember angular vient avec toutes les cloches et sifflets allumés et c'est à vous de les atténuer. Voici quelques directives que j'ai créées pour vous aider. Toutes les données de votre application ne doivent pas nécessairement être liées dans les deux sens et, par conséquent, vous pouvez économiser une précieuse puissance de processeur en renonçant aux expressions de surveillance dans la page si nécessaire. Toutes ces directives lient les données une fois et les laissent seules.

https://Gist.github.com/btm1/6802599

https://Gist.github.com/btm1/6802312

https://Gist.github.com/btm1/674615

L'une des réponses ci-dessus parle de ng-repeat ayant d'énormes succès de performance, donc je vous donne "set-repeat" une directive de répétition de liaison de données unique :)

21
btm1

Il est difficile de fournir une solution sans plus d'informations sur votre problème, mais j'ai récemment rencontré (et résolu) n problème de performances qui peut être similaire à ce que vous avez vu et n'était pas lié au cycle $ digest.

La plupart des discussions sur les performances angularjs que vous trouverez (y compris le excellent article de Misko ) portent sur les performances de la vérification incorrecte et du cycle $ digest. Mais ce n'est pas le seul problème de performances que vous pouvez rencontrer avec angularjs. La première étape devrait être de déterminer si le cycle de digestion est votre problème ou non. Pour cela, vous pouvez utiliser le batarang, ou simplement regarder votre application et quand précisément elle est lente. Lorsque le cycle de digestion est lent, pratiquement toute interaction avec l'interface utilisateur sera lente.

OTOH, vous pouvez avoir une application avec un cycle de résumé rapide, qui n'est lent que lors du chargement, de la commutation des vues ou de la modification des ensembles de composants à afficher, et cela peut se manifester dans le profilage comme beaucoup de temps passé à analyser HTML et les ordures collecte. Dans mon cas, cela a été résolu en effectuant un pré-calcul du modèle html à afficher, au lieu de compter sur ng-repeat, ng-switch, ng-if partout.

J'utilisais un ng-repeat = "widget in widgets" contenant un ng-switch sur le type de widget, pour afficher un ensemble arbitraire de widgets (directives autonomes personnalisées). Remplacer cela par du code pour générer le modèle angular pour l'ensemble spécifique de widgets accéléré en passant de ~ 10 s à pratiquement instantané.

Vous pouvez voir le fil des groupes Google ci-dessus pour un peu plus d'informations sur la façon dont j'ai résolu mon problème particulier, ou fournir plus d'informations sur votre application si vous souhaitez des suggestions spécifiques.

8
jssebastian

Pour améliorer les performances de production, lisez très gentil une ligne ci-dessous:

Citant la documentation AngularJS:

Par défaut, AngularJS attache des informations sur la liaison et les étendues aux nœuds DOM et ajoute des classes CSS aux éléments liés aux données:

À la suite d'interpolations ngBind, ngBindHtml ou {{...}}, les données de liaison et la classe CSS ng-binding sont attachées à l'élément correspondant.

Lorsque le compilateur a créé une nouvelle étendue, l'étendue et la classe CSS ng-scope ou ng-isolated-scope sont attachées à l'élément correspondant. Ces références d'étendue sont ensuite accessibles via element.scope () et element.isolateScope ().

Des outils comme Protractor et Batarang ont besoin de ces informations pour fonctionner, mais vous pouvez les désactiver en production pour une amélioration significative des performances avec:

myApp.config(['$compileProvider', function ($compileProvider) {
  $compileProvider.debugInfoEnabled(false);
}]);

Vous pouvez lire plus de détails ici

4
Abbasi

Généralement, AngularJS fonctionnera mal s'il y a plus de 2000 liaisons de données actives, c'est-à-dire 2000 éléments dans la portée qui sont mal vérifiés à chaque cycle de $ digest. Ng-repeat a un gros impact sur les performances à cause de cela; chaque élément répété configure au moins deux liaisons, sans compter les données ou directives supplémentaires utilisées à l'intérieur de l'élément.

L'un des développeurs derrière AngularJS donne une excellente description des détails de la vérification de la saleté et de ses performances dans cette réponse SO:

https://stackoverflow.com/a/9693933/179024

Le fil de commentaires sous cette réponse mérite d'être lu, et je partage également quelques réflexions à ce sujet dans une réponse plus bas sur la même page:

https://stackoverflow.com/a/18381836/179024

3
MW.

Je suis désolé de l'avoir mis comme "réponse" car je n'ai pas encore assez de points pour faire un commentaire.

Nous avons rencontré des problèmes similaires avec notre application AngularJS. En utilisant "batarang", il semble avoir à gérer un grand nombre d'objets de portée et leurs expressions $ watch pertinentes créent un hoquet de performance. Cela nous a amenés à nous demander si un autre framework ou quelque chose comme ReactJS devrait être utilisé à la place pour s'occuper de la partie "vue".

2
5122014009

essayez d'éviter ce qui suit

  1. veuillez éviter d'utiliser ng-repeat si vous avez plus de 50 éléments dans la liste à la fois et évitez les montres manuelles
  2. n'utilisez pas les événements de souris ng-click, ng-mouseenter, ng-mouseleave etc. à l'aveuglette jusqu'à ce que ce soit un besoin urgent, essayez de réduire leur nombre en utilisant $ event object avec les concepts de propagation d'événements de js

  3. dans la mesure du possible, utilisez scope. $ digest au lieu de scope. $ watch, cela garantit que le cycle de résumé est exécuté uniquement sur les étendues enfants

    1. essayez d'avoir des étendues imbriquées, c'est-à-dire un ou deux contrôleurs à l'intérieur d'un contrôleur parent et conservez la logique réutilisable dans le parent, je l'ai utilisé dans des états imbriqués lors de l'utilisation du routeur Ui (pour répondre à une demande où un changement d'URL était requis sans actualisation de la page).

    le plus important! SUPPRIMER TOUS LES FILTRES DE HTML!

tout ce qui précède déclenche un cycle de résumé sur toutes les étendues de votre application, il y a donc une forte probabilité que même lorsque la vue a été rendue angular exécute à nouveau des boucles de résumé implacables

2
Rishul Matta

Un moyen terme entre le déplacement de la manipulation DOM dans des directives personnalisées et les problèmes de $ watch avec de nombreuses montres $ est d'utiliser la sémantique "bind-once".

C'est idéal pour les données qui sont immuables une fois que les données sont rendues disponibles. Voir bindonce

1
user239558

Ce ne sera qu'un lien! C'est juste une idée que j'ai eue en lisant ceci, je n'ai pas encore exploré cela mais quelqu'un l'a probablement fait alors j'attends leur réponse sur mon idée. Que diriez-vous d'utiliser des travailleurs Web partagés pour obtenir beaucoup de traitement lourd sur le thread d'interface utilisateur? https://github.com/h2non/sharedworkers-angular-poc

L'autre idée que j'ai eue était plus simple. Votre application bénéficierait-elle d'un défilement infini? Je veux dire que ces formulaires ne tiennent probablement pas tous sur l'écran, ils ne sont pas connectés les uns aux autres, alors pourquoi ne pas les dessiner comme ils sont nécessaires? Chargez-les en mémoire puis dessinez-les en conséquence.

0
Zoneh

Comme dans toute autre optimisation des performances, il est important de savoir comment profiler l'application pour trouver le véritable goulot d'étranglement. Ensuite, vous pouvez les résoudre un par un. Je combat généralement les goulots d'étranglement dans l'ordre suivant:

  • mon code javascript
  • expressions angulaires (observateurs et filtres complexes) qui s'exécutent à chaque cycle de résumé inactif
  • constructions angulaires (ng-repeat, copie d'objets pour le cycle de résumé)

J'ai profilé un angular étape par étape montrant comment identifier un goulot d'étranglement à chaque étape. http://bahmutov.calepin.co/improving-angular-web-app- performance-example.html

0
gleb bahmutov