Leistung mit unendlicher Schriftrolle oder vielen Dom-Elementen?


76

Ich habe eine Frage zu einer großen Anzahl von Dom elmenets und Leistungen.

Angenommen, ich habe 6000 Dom-Elemente auf einer Seite und die Anzahl der Elemente kann erhöht werden, wenn ein Benutzer mit der Seite interagiert (Benutzer scrollt, um ein neues Dom-Element zu erstellen), wie z. B. Twitter.

Um die Leistung der Seite zu verbessern, kann ich mir nur zwei Dinge vorstellen.

  1. Setzen Sie die Anzeige auf keine unsichtbaren Elemente, um einen Reflow zu vermeiden
  2. Entfernen Sie unsichtbare Elemente aus dem Dom und fügen Sie sie nach Bedarf hinzu.

Gibt es andere Möglichkeiten, eine Seite mit vielen Dom-Elementen zu verbessern?


3
Wenn Sie die Anzeige auf "Keine" setzen, wird ein Reflow ausgelöst, der völlig entgegengesetzt zu dem ist, was Sie möchten, wenn Sie einen Reflow vermeiden möchten. Wenn Sie nichts tun, wird kein Reflow ausgelöst. Wenn Sie die Sichtbarkeit auf "Ausgeblendet" setzen, wird auch kein Reflow ausgelöst. Es ist jedoch nicht viel einfacher, etwas zu tun.
Slebetman

3
Sie sollten sich auch bewusst sein, dass Ihr Fenstermanager bereits unsichtbare Pixel vom Bildschirm entfernt, um die Interaktion mit der Benutzeroberfläche zu beschleunigen. Wenn Sie es selbst in Javascript tun, werden die Dinge wahrscheinlich langsamer, anstatt sie zu beschleunigen.
Slebetman

@slebetman // Wenn ich die Anzeige auf none setze, wird ein Reflow ausgelöst. Das ist richtig. Aber ... wenn Sie scrollen, löst dies auch einen Reflow aus und der Browser muss das Layout für alle Elemente auf der Seite berechnen. Ich dachte, dass die Einstellung "Keine anzeigen" für einige Elemente auf der Seite dazu beitragen würde, die Berechnungszeit für das Layout zu verkürzen.
Mond

1
Nein, tut es nicht. Sie können es selbst überprüfen, indem Sie Firefox oder Chrome mit aktiviertem Debug kompilieren und über einen Profiler ausführen. Das Scrollen löst Neulackierungen aus, alle Scrollen in allen Programmen, auch Word oder Notepad, lösen Neulackierungen aus. Selbst das Bewegen des Mauszeigers löst Neulackierungen aus. Aber Repaints sind billig - sie wurden bereits seit Ende der 1980er Jahre optimiert und werden vom Betriebssystem / Fenstermanager selbst und nicht vom Programm implementiert. Das Scrollen löst keinen Reflow aus.
Slebetman

1
@slebetman // ah..Ich habe einen Eindruck von Scroll Reflow von paulirish.com/2011/dom-html5-css3-performance Video bekommen. Das Video listet auf, dass window.scrollBy einen Reflow verursacht. Ich frage mich, warum das so ist, wenn die Schriftrolle des Benutzers dies nicht tut.
Mond

Antworten:


26

Ich habe noch keine Erfahrung damit, aber hier gibt es einige großartige Tipps: http://engineering.linkedin.com/linkedin-ipad-5-techniques-smooth-infinite-scrolling-html5

Ich habe mir Facebook angesehen und sie scheinen auf Firefox nichts Besonderes zu tun. Während Sie nach unten scrollen, ändern sich die DOM-Elemente oben auf der Seite nicht. Die Speichernutzung von Firefox steigt auf etwa 500 Megabyte, bevor Facebook Ihnen nicht erlaubt, weiter zu scrollen.

Twitter scheint dasselbe zu sein wie Facebook.

Google Maps ist eine andere Geschichte - nicht sichtbare Kartenkacheln werden aus dem DOM entfernt (wenn auch nicht sofort).


1
// Vielen Dank, dass Sie sich die Zeit genommen haben, Ihren Fund zu untersuchen. Ich werde das gleiche bald tun.
Mond

2
Es wäre wirklich interessant zu sehen, wie Pinterest das macht. Sie scheinen es herausgefunden zu haben, als sie Elemente dynamisch laden, während Sie nach unten und hinten scrollen. Sie scheinen immer eine festgelegte Anzahl von Pins zu einem bestimmten Zeitpunkt auf der Feed-Seite geladen zu haben.
alex

103

Wir mussten uns mit einem ähnlichen Problem bei FoldingText befassen . Mit zunehmender Größe des Dokuments wurden mehr Linienelemente und zugehörige Bereichselemente erstellt. Die Browser-Engine schien nur zu ersticken, und so musste eine bessere Lösung gefunden werden.

Folgendes haben wir getan, können für Ihre Zwecke nützlich sein oder auch nicht:

Visualisieren Sie die gesamte Seite als langes Dokument und das Browser-Ansichtsfenster als Objektiv für einen bestimmten Teil des langen Dokuments. Sie müssen wirklich nur den Teil innerhalb des Objektivs zeigen.

Der erste Teil besteht also darin, den sichtbaren Ansichtsport zu berechnen. (Dies hängt davon ab, wie Ihre Elemente platziert sind, absolut / fest / Standard)

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

Weitere Ressourcen, um ein browserübergreifenderes Ansichtsfenster zu finden:

Holen Sie sich die Dimensionen des Browser-Ansichtsfensters mit JavaScript

Browserübergreifende Methode zum Erkennen des scrollTop des Browserfensters

Zweitens benötigen Sie eine Datenstruktur, um zu wissen, welche Elemente in diesem Bereich sichtbar sind

Wir hatten bereits einen ausgeglichenen binären Suchbaum für die Textbearbeitung, daher haben wir ihn erweitert, um auch die Zeilenhöhen zu verwalten, sodass dieser Teil für uns relativ einfach war. Ich glaube nicht, dass Sie eine komplexe Datenstruktur für die Verwaltung Ihrer Elementhöhen benötigen. Ein einfaches Array oder Objekt kann gut funktionieren. Stellen Sie einfach sicher, dass Sie Höhen und Maße einfach abfragen können. Wie würden Sie nun die Höhendaten für alle Ihre Elemente erhalten? Eine sehr einfache (aber rechenintensive für große Mengen von Elementen!)

var boundingRect = element.getBoundingClientRect()

Ich bin in Bezug auf die reine Javascript sprechen, aber wenn Sie jQuery verwenden $.offset, $.positionund Methoden aufgeführt hier wäre sehr hilfreich.

Auch hier ist die Verwendung einer Datenstruktur nur als Cache wichtig. Wenn Sie möchten, können Sie dies jedoch im laufenden Betrieb tun (obwohl diese Vorgänge, wie bereits erwähnt, teuer sind). Achten Sie auch darauf, die CSS-Stile zu ändern und diese Methoden aufzurufen. Diese Funktionen erzwingen das Neuzeichnen, sodass ein Leistungsproblem auftritt.

Zuletzt ersetzen Sie einfach die Elemente außerhalb des Bildschirms durch ein einzelnes, beispielsweise <div>Element mit berechneter Höhe

  • Jetzt haben Sie Höhen für alle in Ihrer Datenstruktur gespeicherten Elemente. Fragen Sie alle Elemente ab, die vor dem sichtbaren Ansichtsfenster liegen.

  • Erstellen Sie eine <div>mit CSS-Höhe festgelegte Höhe (in Pixel) zur Summe der Elementhöhen

  • Markieren Sie es mit einem Klassennamen, damit Sie wissen, dass es sich um ein Füller-Div handelt
  • Entfernen Sie alle Elemente aus dem Dom, den dieses Div abdeckt
  • Fügen Sie stattdessen dieses neu erstellte Div ein

Wiederholen Sie diesen Vorgang für Elemente, die hinter dem sichtbaren Ansichtsfenster liegen.

Suchen Sie nach Ereignissen zum Scrollen und Ändern der Größe. Bei jedem Bildlauf müssen Sie zu Ihrer Datenstruktur zurückkehren, die Füller-Divs entfernen, Elemente erstellen, die zuvor vom Bildschirm entfernt wurden, und dementsprechend neue Füller-Divs hinzufügen.

:) Es ist eine lange, komplexe Methode, aber bei großen Dokumenten hat sie unsere Leistung erheblich gesteigert.

tl; dr

Ich bin mir nicht sicher, ob ich es richtig erklärt habe, aber der Kern dieser Methode ist:

  • Kennen Sie die vertikalen Abmessungen Ihrer Elemente
  • Kennen Sie den gescrollten Ansichtsport
  • Stellen Sie alle Off-Screen-Elemente mit einem einzigen Div dar (Höhe entspricht der Summe aller Elementhöhen, für die es gilt)
  • Sie benötigen zu jedem Zeitpunkt insgesamt zwei Divs, einen für Elemente über dem sichtbaren Ansichtsfenster und einen für Elemente darunter.
  • Behalten Sie den Überblick über das Ansichtsfenster, indem Sie auf Bildlauf- und Größenänderungsereignisse warten. Erstellen Sie die Divs und sichtbaren Elemente entsprechend neu

Hoffe das hilft.


// Das macht Sinn! Vielen Dank für Ihren Einblick!
Mond

Können Sie ein Beispiel für einen Fall geben, in dem eine komplexe Datenstruktur erforderlich wäre?
Joren Van Severen

3
Übrigens habe ich festgestellt, dass dies die einzige Möglichkeit ist, viele DOM-Elemente mit einer noch vernünftigen Bildlauferfahrung zu verarbeiten. Das Abrufen von scrollTop im Scroll-Handler (jquery) führt außerdem nicht zu einem erneuten Zeichnen. Tatsächlich wird die Warteschlange nur von Neuzeichnungen und Neuanstrichen gelöscht, sodass das zuletzt aktuelle scrollTop zurückgegeben werden kann. Ich vermute, dass es zu dem Zeitpunkt, an dem das Scrollevent gehandhabt wird, bereits auf dem neuesten Stand ist.
Joren Van Severen

1
@JorenVanSeveren Es hängt von Ihrem Bedarf an komplexen Datenstrukturen ab. Wie gesagt, wir haben einen ausgeglichenen Binärbaum verwendet, weil wir bereits einen hatten. Ich glaube nicht, dass Sie es brauchen werden, um NUR die Höhen des Doms zu verwalten.
Mutahhir

8
@Moon: Dieselbe Technik, die in dieser Antwort beschrieben wird, wurde in Form eines Plugins implementiert. ClusterizeJS . Funktioniert genau wie erwartet und unterstützt bei Bedarf auch die Artikelparität. Und es funktioniert wirklich toll! (Zu Ihrer Information: Ich bin kein Entwickler davon)
Robert Koritnik

8

Es ist 2019. Die Frage ist wirklich alt, aber ich denke, sie ist immer noch relevant und interessant und vielleicht hat sich bis heute etwas geändert, da wir alle jetzt auch dazu neigen, React JS zu verwenden.

Mir ist aufgefallen, dass in der Zeitleiste von Facebook scheinbar Inhaltscluster verwendet werden, die ausgeblendet display: none !importantwerden, sobald der Cluster nicht mehr angezeigt wird. Daher werden alle zuvor gerenderten Elemente des DOM im DOM gespeichert. Es ist nur so, dass diejenigen, die nicht angezeigt werden, ausgeblendet werden display: none !important. Außerdem wird die Gesamthöhe des ausgeblendeten Clusters auf das übergeordnete Element divdes ausgeblendeten Clusters festgelegt.

Hier sind einige Screenshots, die ich gemacht habe:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Was halten Sie ab 2019 von diesem Ansatz? Wie kann React für diejenigen, die React verwenden, in React implementiert werden? Es wäre toll, Ihre Meinungen und Gedanken zu diesem kniffligen Thema zu erhalten.

Danke für die Aufmerksamkeit!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.