web-dev-qa-db-fra.com

Des performances avec un défilement infini ou beaucoup d'éléments dom?

J'ai une question sur un grand nombre d'elmenets dom et de performances.

Disons que j'ai 6000 éléments dom sur une page et que le nombre d'éléments peut être augmenté à mesure qu'un utilisateur interagit avec la page (l'utilisateur fait défiler pour créer un nouvel élément dom) comme Twitter.

Pour améliorer les performances de la page, je ne peux penser qu'à deux choses.

  1. définissez l'affichage sur aucun pour les éléments invisibles pour éviter la refusion
  2. supprimez les éléments invisibles du dom puis ajoutez-les à nouveau au besoin.

Y a-t-il d'autres façons d'améliorer une page avec beaucoup d'éléments dom?

67
Moon

Aucune expérience moi-même avec cela, mais il y a quelques bons conseils ici: http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5

J'ai jeté un œil à Facebook et ils ne semblent rien faire de particulier sur Firefox. Lorsque vous faites défiler vers le bas, les éléments DOM en haut de la page ne changent pas. L'utilisation de la mémoire de Firefox grimpe à environ 500 mégaoctets avant que Facebook ne vous permette de faire défiler plus loin.

Twitter semble être le même que Facebook.

Google Maps est une histoire différente - les tuiles de carte hors de vue sont supprimées du DOM (mais pas immédiatement).

24
cbp

Nous avons dû faire face à un problème similaire sur FoldingText . À mesure que le document devenait plus grand, davantage d'éléments de ligne et d'éléments de travée associés ont été créés. Le moteur du navigateur semblait juste s'étouffer, et donc une meilleure solution devait être trouvée.

Voici ce que nous avons fait, peut ou peut ne pas être utile à vos fins:

Visualisez la page entière comme un document long et la fenêtre du navigateur comme objectif pour une partie spécifique du document long. Vous n'avez vraiment qu'à montrer la pièce dans l'objectif.

La première partie consiste donc à calculer le port de vue visible. (Cela dépend de la façon dont vos éléments sont placés, absolu/fixe/par défaut)

var top = document.scrollTop;
var width = window.innerWidth;
var height = window.innerHeight;

Quelques ressources supplémentaires pour trouver une fenêtre plus basée sur plusieurs navigateurs:

Obtenez les dimensions de la fenêtre du navigateur avec JavaScript

Méthode multi-navigateur pour détecter le scrollTop de la fenêtre du navigateur

Deuxièmement, vous avez besoin d'une structure de données pour savoir quels éléments sont visibles dans cette zone

Nous avions déjà un arbre de recherche binaire équilibré en place pour l'édition de texte, nous l'avons donc étendu pour gérer également les hauteurs de ligne, donc cette partie pour nous était relativement facile. Je ne pense pas que vous aurez besoin d'une structure de données complexe pour gérer la hauteur de vos éléments; un simple tableau ou objet pourrait bien faire l'affaire. Assurez-vous simplement de pouvoir interroger facilement les hauteurs et les dimensions. Maintenant, comment obtiendriez-vous les données de hauteur pour tous vos éléments. Un très simple (mais coûteux en calcul pour de grandes quantités d'éléments!)

var boundingRect = element.getBoundingClientRect()

Je parle en termes de javascript pur, mais si vous utilisez jQuery $.offset, $.position, et les méthodes listées ici seraient très utiles.

Encore une fois, l'utilisation d'une structure de données n'est importante que comme cache, mais si vous le souhaitez, vous pouvez le faire à la volée (bien que, comme je l'ai dit, ces opérations soient coûteuses). Méfiez-vous également de changer les styles CSS et d'appeler ces méthodes. Ces fonctions forcent le redessin, vous verrez donc un problème de performances.

Enfin, remplacez simplement les éléments hors écran par un seul, par exemple <div> élément avec hauteur calculée

  • Maintenant, vous avez des hauteurs pour tous les éléments stockés dans votre structure de données, interrogez tous les éléments qui se trouvent avant la fenêtre visible.

  • Créer un <div> avec la hauteur css définie (en pixels) à la somme des hauteurs des éléments

  • Marquez-le avec un nom de classe afin que vous sachiez que c'est un div de remplissage
  • Retirez tous les éléments du dom que ce div couvre
  • insérez ce div nouvellement créé à la place

Répétez l'opération pour les éléments situés après la fenêtre visible.

Recherchez les événements de défilement et de redimensionnement. Sur chaque défilement, vous devrez revenir à votre structure de données, supprimer les diviseurs de remplissage, créer des éléments qui ont été précédemment supprimés de l'écran et ajouter en conséquence de nouveaux diviseurs de remplissage.

:) C'est une méthode longue et complexe, mais pour les gros documents, elle a augmenté nos performances d'une grande marge.

tl; dr

Je ne suis pas sûr de l'avoir expliqué correctement, mais l'essentiel de cette méthode est:

  • Connaître les dimensions verticales de vos éléments
  • Connaître le port d'affichage défilé
  • Représenter tous les éléments hors écran avec un seul div (hauteur égale à la somme de toutes les hauteurs d'élément qu'il couvre)
  • Vous aurez besoin de deux divs au total à tout moment, un pour les éléments au-dessus de la fenêtre visible, un pour les éléments ci-dessous.
  • Gardez une trace du port d'affichage en écoutant les événements de défilement et de redimensionnement. Recréez les divs et les éléments visibles en conséquence

J'espère que cela t'aides.

95
Mutahhir

Nous sommes en 2019. La question est vraiment ancienne, mais je pense qu'elle est toujours pertinente et intéressante et peut-être que quelque chose a changé à partir d'aujourd'hui, car nous avons tous aussi tendance à utiliser React JS.

J'ai remarqué que la chronologie de Facebook semble utiliser des clusters de contenu qui sont cachés avec display: none !important dès que le cluster est hors de vue, donc tous les éléments précédemment rendus du DOM sont conservés dans le DOM, c'est juste que ceux hors de vue sont cachés avec display: none !important. En outre, la hauteur globale du cluster masqué est définie sur le parent div du cluster masqué.

Voici quelques captures d'écran que j'ai faites:

enter image description here

enter image description here

enter image description here

À partir de 2019, que pensez-vous de cette approche? De plus, pour ceux qui utilisent React, comment pourrait-il être implémenté dans React? Ce serait formidable de recevoir vos opinions et réflexions sur ce sujet délicat.

Merci pour l'attention!

1
tonix