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/

11voto

bartekp Points 301

Si toutes vos lignes ont la même hauteur, vous devriez certainement jeter un coup d'œil à la virtualisation de ng-repeat : http://kamilkp.github.io/angular-vs-repeat/

Este Démonstration semble très prometteur (et il supporte le défilement inertiel)

2 votes

Les performances de défilement sur le mobile ne sont pas acceptables (les événements de défilement ne se déclenchent pas sur le mobile iOS (seulement en hausse par rapport à 8).

10voto

Sarantis Tofas Points 3398

Défilement virtuel est un autre moyen d'améliorer les performances de défilement lors du traitement de listes et d'ensembles de données volumineux.

Une façon de mettre cela en œuvre est d'utiliser Matériau angulaire md-virtual-repeat comme cela est démontré sur ce Démonstration avec 50 000 articles

Tiré directement de la documentation de la répétition virtuelle :

La répétition virtuelle est un substitut limité de ng-repeat qui ne rend que suffisamment de nœuds dom pour remplir le conteneur et les recycle au fur et à mesure que l'utilisateur défile.

9voto

Steffomio Points 305

Règle n° 1 : ne laissez jamais l'utilisateur attendre quoi que ce soit.

Cela dit, une page qui s'étoffe et qui nécessite 10 secondes s'affiche bien plus rapidement que si vous attendez 3 secondes devant un écran vide et que vous obtenez tout d'un coup.

Ainsi, au lieu de faire la page rapidement, il suffit de laisser la page apparaître pour être rapide, même si le résultat final est plus lent :

function applyItemlist(items){
    var item = items.shift();
    if(item){
        $timeout(function(){
            $scope.items.push(item);
            applyItemlist(items);
        }, 0); // <-- try a little gap of 10ms
    }
}

Le code ci-dessus laisse apparaître la liste en croissance ligne par ligne, et est toujours plus lent qu'un rendu en une seule fois. Mais pour l'utilisateur il semble être plus rapide.

7voto

Luevano Points 131

Une autre version @Steffomio

Au lieu d'ajouter chaque élément individuellement, nous pouvons ajouter des éléments par morceaux.

// chunks function from here: 
// http://stackoverflow.com/questions/8495687/split-array-into-chunks#11764168
var chunks = chunk(folders, 100);

//immediate display of our first set of items
$scope.items = chunks[0];

var delay = 100;
angular.forEach(chunks, function(value, index) {
    delay += 100;

    // skip the first chuck
    if( index > 0 ) {
        $timeout(function() {
            Array.prototype.push.apply($scope.items,value);
        }, delay);
    }       
});

0voto

UniCoder Points 1124

Parfois, ce qui s'est passé, vous obtenez les données du serveur (ou du back-end) en quelques ms (par exemple, je suppose que c'est 100ms) mais il faut plus de temps pour afficher dans notre page web (disons que l'affichage prend 900 ms).

Donc, ce qui se passe ici, c'est que 800 ms sont nécessaires pour rendre la page web.

Ce que j'ai fait dans mon application web, c'est que j'ai utilisé pagination (ou vous pouvez utiliser défilement infini également) pour afficher la liste des données. Disons que j'affiche 50 données par page.

Je ne vais donc pas charger toutes les données en une seule fois, mais seulement 50 données que je charge initialement, ce qui ne prend que 50 ms (je suppose ici).

Ainsi, le temps total a diminué de 900 ms à 150 ms, une fois que l'utilisateur demande la page suivante, il affiche les 50 données suivantes et ainsi de suite.

J'espère que cela vous aidera à améliorer les performances. Nous vous souhaitons bonne chance.

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