165 votes

Comment améliorer les performances de ngRepeat sur un énorme jeu de données (angular.js) ?

J'ai un énorme ensemble de données de plusieurs milliers de lignes avec environ 10 champs chacune, soit environ 2 Mo de données. J'ai besoin de les afficher dans le navigateur. L'approche la plus simple (récupérer les données, les mettre dans un fichier de type $scope laissons ng-repeat="" faire son travail) fonctionne bien, mais il bloque le navigateur pendant environ une demi-minute lorsqu'il commence à insérer des nœuds dans le DOM. Comment dois-je aborder ce problème ?

Une option consiste à ajouter des lignes à $scope de manière incrémentielle et attendre que ngRepeat pour finir d'insérer un morceau dans le DOM avant de passer au suivant. Mais, pour l'instant, ngRepeat ne signale pas quand il a fini de "répéter", donc ça va être moche.

L'autre option consiste à diviser les données sur le serveur en pages et à les récupérer en plusieurs requêtes, mais c'est encore plus laid.

J'ai parcouru la documentation d'Angular à la recherche de quelque chose comme ng-repeat="data in dataset" ng-repeat-steps="500" mais je n'ai rien trouvé. Je suis assez nouveau dans les méthodes Angular, il est donc possible que je manque complètement le point. Quelles sont les meilleures pratiques en la matière ?

10 votes

Voulez-vous vraiment afficher TOUTES les lignes ? Pourquoi ne pas afficher seulement le nombre de lignes que l'utilisateur peut voir ? Par exemple, vous pourriez utiliser limitTo pour afficher seulement 20 éléments : <p ng-repeat="data in dataset | limitTo:20">{{data}}</p> Cela ne montre que 20 articles. Vous pourriez alors utiliser des pages et afficher les 10 éléments suivants ou quelque chose du genre :)

0 votes

Pour ce qui est de "rapporter quand il a fini de se répéter", vous pouvez utiliser une directive personnalisée en plus de ng-repeat. (voir ici la réponse sélectionnée) stackoverflow.com/questions/13471129/

0 votes

Référez-vous à cette question, elle vous aidera sûrement. [entrer la description du lien ici] [1] [1] : stackoverflow.com/questions/25481021/

160voto

Bema Points 4128

Je suis d'accord avec @AndreM96 que la meilleure approche est d'afficher seulement une quantité limitée de lignes, plus rapide et meilleure UX, cela pourrait être fait avec une pagination ou avec un scroll infini.

Le scroll infini avec Angular est vraiment simple avec limitTo filtre. Il suffit de fixer la limite initiale et lorsque l'utilisateur demande plus de données (j'utilise un bouton pour simplifier), vous incrémentez la limite.

<table>
    <tr ng-repeat="d in data | limitTo:totalDisplayed"><td>{{d}}</td></tr>
</table>
<button class="btn" ng-click="loadMore()">Load more</button>

//the controller
$scope.totalDisplayed = 20;

$scope.loadMore = function () {
  $scope.totalDisplayed += 20;  
};

$scope.data = data;

Voici un JsBin .

Cette approche peut poser un problème pour les téléphones, car ils sont généralement lents lorsqu'ils font défiler beaucoup de données. Dans ce cas, je pense qu'une pagination est plus adaptée.

Pour ce faire, vous aurez besoin du filtre limitTo ainsi que d'un filtre personnalisé pour définir le point de départ des données affichées.

Voici un JSBin avec une pagination.

0 votes

Belle alternative ! !! Vous connaissez une méthode à utiliser si je suis tenu de montrer tous les éléments. un signe de chargement ou une insertion un après l'autre dans le DOM ou quelque chose ?

0 votes

Voulez-vous dire afficher un "chargement..." ou quelque chose d'autre pendant que les données sont récupérées ?

0 votes

Pouvez-vous me fournir un exemple pour charger des données lors du défilement ? Je ne veux pas que l'utilisateur clique sur le bouton "load more data", il serait préférable de charger les données lorsque l'utilisateur arrive à la fin du défilement. J'ai essayé de trouver les choses mais je n'ai pas trouvé de solution appropriée avec Angular.

42voto

XMLilley Points 2351

L'approche la plus moderne - et sans doute la plus évolutive - pour surmonter ces défis avec de grands ensembles de données est incarnée par l'approche de La directive collectionRepeat de Ionic et d'autres implémentations similaires. Un terme sophistiqué pour cela est élimination des occlusions Mais on peut le résumer ainsi : ne limitez pas simplement le nombre d'éléments DOM rendus à un nombre arbitraire (mais toujours élevé) paginé comme 50, 100, 500... à la place, se limiter à autant d'éléments que l'utilisateur peut voir .

Si vous faites quelque chose comme ce que l'on appelle communément le "défilement infini", vous réduisez l'espace de travail de l'utilisateur. initial Le DOM compte un peu, mais il gonfle rapidement après quelques rafraîchissements, car tous ces nouveaux éléments sont simplement ajoutés en bas de page. Le défilement devient un jeu d'enfant, parce que le défilement est une question de nombre d'éléments. Il n'y a rien d'infini là-dedans.

considérant que le collectionRepeat L'approche consiste à n'utiliser que le nombre d'éléments pouvant s'insérer dans la fenêtre d'affichage. les recycler . Lorsqu'un élément tourne hors de vue, il est détaché de l'arbre de rendu, rempli de données pour un nouvel élément de la liste, puis rattaché à l'arbre de rendu à l'autre extrémité de la liste. C'est le moyen le plus rapide connu de l'homme pour faire entrer et sortir de nouvelles informations du DOM, en utilisant un ensemble limité d'éléments existants, plutôt que le cycle traditionnel de création/destruction... création/destruction. En utilisant cette approche, vous pouvez véritablement mettre en œuvre un infini défilement.

Notez que vous n'êtes pas obligé d'utiliser Ionic pour utiliser/hack/adaptation collectionRepeat ou tout autre outil similaire. C'est pourquoi ils l'appellent open-source :-) (Cela dit, l'équipe Ionic fait des choses assez ingénieuses, qui méritent votre attention).


Il y a au moins un excellent exemple de faire quelque chose de très similaire dans React. Seulement, au lieu de recycler les éléments avec un contenu mis à jour, vous choisissez simplement de ne pas rendre ce qui n'est pas visible dans l'arbre. C'est très rapide sur 5000 éléments, bien que leur implémentation POC très simple permette un peu de scintillement...


De plus... pour faire écho à d'autres messages, l'utilisation de track by est très utile, même avec de petits ensembles de données. Considérez-le comme obligatoire.

36voto

user3384055 Points 111

Je vous recommande de voir ça :

Optimisation d'AngularJS : 1200ms à 35ms

ils ont fait une nouvelle directive en optimisant ng-repeat à 4 parties :

Optimisation#1 : Mettre en cache les éléments du DOM

Optimisation n°2 : Agrégation des surveillants

Optimisation n°3 : reporter la création des éléments

Optimisation#4 : Contourner les surveillants pour les éléments cachés

le projet est ici sur github :

Utilisation :

1- inclure ces fichiers dans votre application à page unique :

  • core.js
  • scalyr.js
  • slyEvaluate.js
  • slyRepeat.js

2- ajouter la dépendance du module :

var app = angular.module("app", ['sly']);

3- remplacer ng-repeat

<tr sly-repeat="m in rows"> .....<tr>

ENjoY !

15voto

Shilan Points 550

En plus de tous les conseils ci-dessus, comme la piste par et les petites boucles, celui-ci m'a également beaucoup aidé.

<span ng-bind="::stock.name"></span>

ce morceau de code imprimerait le nom une fois qu'il a été chargé, et cesserait de le regarder après cela. De même, pour ng-repeats, il pourrait être utilisé comme suit

<div ng-repeat="stock in ::ctrl.stocks">{{::stock.name}}</div>

mais il ne fonctionne que pour AngularJS version 1.3 et supérieure. À partir de http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/

12voto

user1920302 Points 171

Vous pouvez utiliser "track by" pour augmenter les performances :

<div ng-repeat="a in arr track by a.trackingKey">

Plus vite que :

<div ng-repeat="a in arr">

réf : https://www.airpair.com/angularjs/posts/angularjs-performance-large-applications

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X