Faules Laden von Bildern mit IntersectionObserver

Heutzutage sind Bilder der Hauptstolperstein auf dem Weg zu Hochgeschwindigkeitsladestellen. Dies gilt insbesondere für E-Commerce-Projekte. Bilder auf ihnen, normalerweise ziemlich "schwer", machen den größten Teil des Inhalts der Seiten aus. Dies führt in der Regel dazu, dass sein Browser mehrere Megabyte Grafikdaten herunterladen muss, um dem Benutzer eine Seite anzuzeigen. Wie kann das Laden von Seiten in dieser Situation beschleunigt werden? Die Antwort auf diese Frage ist dem Material gewidmet, dessen Übersetzung wir heute veröffentlichen.

Bild

Allgemeine Bestimmungen


Betrachten Sie zum Beispiel die Startseite der Home- Abteilung bei Walmart.


Eine Seite mit vielen Bildern

Hier finden Sie Informationen dazu, wie viele Bilder geladen werden, um diese Seite zu erstellen:


Bilder, die während der Seitenbildung geladen wurden

Wie Sie sehen können, gibt es 137 Bilder! Dies bedeutet, dass mehr als 80% der Daten, die zum Anzeigen der Seite benötigt und über das Netzwerk übertragen werden, als Grafikdateien dargestellt werden.

Jetzt analysieren wir die Netzwerkanforderungen, die beim Laden der Seite ausgeführt werden:


Netzwerkanforderungen, die während der Seitenbildung ausgeführt werden

In diesem Fall werden die Dateien, die sich aus der Trennung des Projektcodes ergeben, später heruntergeladen, als sie könnten. Dies liegt daran, dass Sie zuerst das cp_ny.bundle laden cp_ny.bundle . Dieses Bundle könnte viel schneller heruntergeladen werden, wenn es nicht durch 18 Bilder gestört worden wäre, die miteinander um Bandbreite konkurrieren.

Wie kann ich das beheben? In der Tat funktioniert es nicht, dies wirklich zu „beheben“, aber Sie können viele Dinge tun, um das Laden von Bildern zu optimieren. Es gibt viele Ansätze zur Optimierung von Bildern, die auf Webseiten verwendet werden. Dazu gehören die Verwendung verschiedener Grafikdateiformate, die Datenkomprimierung, die Verwendung von Unschärfe-Animationstechniken und die Verwendung von CDN. Ich möchte auf das sogenannte "Lazy Loading" von Bildern (Lazy Loading) eingehen. Insbesondere werden wir darüber sprechen, wie diese Technik auf React-Sites implementiert wird. Da sie jedoch auf JavaScript-Mechanismen basiert, kann sie in jedes Webprojekt integriert werden.

Pilotprojekt


Beginnen wir mit einer so extrem einfachen Image React-Komponente:

 class Image extends PureComponent { render() {   const { src } = this.props;   return <img align="center" src={src} />; } } 

Als Eigenschaft wird eine URL verwendet und zum Rendern des img HTML-Elements verwendet. Hier ist der relevante JSFiddle-Code. Das folgende Bild zeigt die Seite mit dieser Komponente. Bitte beachten Sie, dass Sie den Inhalt der Seite scrollen müssen, um das von ihm angezeigte Bild zu sehen.


Die Seite mit der Komponente, die das Bild anzeigt

Um die Technik des verzögerten Ladens von Bildern in dieser Komponente zu implementieren, müssen Sie die folgenden drei Schritte ausführen:

  1. Rendern Sie das Bild nicht sofort nach dem Herunterladen.
  2. Richten Sie Tools zum Erkennen des Erscheinungsbilds eines Bildes im Anzeigebereich des Seiteninhalts ein.
  3. Zeigen Sie das Bild an, nachdem festgestellt wurde, dass es in den Anzeigebereich gefallen ist.

Werfen wir einen Blick auf diese Schritte.

Schritt 1


In diesem Schritt wird das Bild unmittelbar nach dem Laden nicht angezeigt.

 render() { return <img />; } 

Schritt 2


Hier konfigurieren wir die Mechanismen, mit denen wir den Moment erkennen können, in dem das Bild in den Betrachtungsbereich gelangt.

 componentDidMount() { this.observer = new IntersectionObserver(() => {   //        }, {   root: document.querySelector(".container") }); this.observer.observe(this.element); } .... render() { return <img ref={el => this.element = el} />; } 

Lassen Sie uns diesen Code analysieren. Folgendes wurde hier getan:

  • Das ref- Attribut wurde dem img Element hinzugefügt. Auf diese Weise können Sie den Image-Link in src später aktualisieren, ohne die Komponente erneut rendern zu müssen.
  • Eine neue Instanz von IntersectionObserver (wir werden weiter unten darauf eingehen).
  • Das IntersectionObserver Objekt wird aufgefordert, das Bild mithilfe des Konstrukts observe(this.element) zu beobachten.

Was ist IntersectionObserver ? Wenn man bedenkt, dass das Wort "Schnittpunkt" als "Schnittpunkt" übersetzt wird und "Beobachter" "Beobachter" ist, kann man bereits die Rolle dieses Objekts erraten. Wenn Sie in MDN nach Informationen dazu suchen, können Sie feststellen, dass die Intersection Observer-API es Webanwendungen ermöglicht, Änderungen an der Schnittmenge eines Elements mit seinem übergeordneten Element oder dem Umfang eines Ansichtsfensterdokuments asynchron zu überwachen.

Auf den ersten Blick mag diese Eigenschaft der API nicht besonders verständlich erscheinen, aber tatsächlich ist sie sehr einfach aufgebaut. Der IntersectionObserver Instanz werden mehrere Parameter übergeben. Insbesondere haben wir den root Parameter verwendet, mit dem wir das Root-DOM-Element, das wir als Container betrachten, um den Schnittpunkt des Elements mit dem Rand setzen können, dessen Rand wir kennen müssen. Standardmäßig ist dies der Bereich, in dem sich das sichtbare Fragment der Seite (Ansichtsfenster) befindet. Ich habe es jedoch explizit so eingestellt, dass der Container im iframe Element der JSFiddle verwendet wird. Dies geschieht, um später eine Möglichkeit in Betracht zu ziehen, die nicht für die Verwendung von iframe Elementen ausgelegt ist.

Der Grund, warum die Verwendung von IntersectionObserver zum Ermitteln, wann ein Element sichtbar wird, beliebter ist als herkömmliche Methoden wie die gemeinsame Verwendung von onScroll und getBoundingClientRect() , da IntersectionObserver Mechanismen außerhalb des Hauptthreads ausgeführt werden. Der Rückruf, der aufgerufen wird, nachdem IntersectionObserver den Schnittpunkt des Elements mit dem Container erkannt hat, wird natürlich im Hauptthread ausgeführt, sodass sein Code nicht zu schwer sein sollte.

Schritt 3


Jetzt müssen wir den Rückruf konfigurieren, der aufgerufen wird, wenn er den Schnittpunkt des this.element (in diesem Fall dieses Element) mit dem this.element erkennt (in unserem Fall handelt es sich um ein div Element .container ).

 .... this.observer = new IntersectionObserver( entries => {   entries.forEach(entry => {     const { isIntersecting } = entry;     if (isIntersecting) {       this.element.src = this.props.src;       this.observer = this.observer.disconnect();     }   }); }, {   root: document.querySelector(".container") } ); .... 

Wenn der Schnittpunkt erkannt wird, wird das Array von entries an den entries , der einer Reihe von Schnappschüssen des Status aller entries ähnelt, für die der Schnittpunkt des angegebenen Rahmens erkannt wird. Die Eigenschaft isIntersecting gibt die Richtung der Kreuzung an. Wenn das überwachte Element außerhalb des Stammelements liegt, ist es true . Wenn ein Element das Stammelement verlässt, ist es false .

Wenn sich herausstellt, dass das Element den unteren Rand des Containers überschritten hat, setze ich seine src Eigenschaft manuell und deaktiviere die Überwachung dafür, was nicht mehr erforderlich ist.

Schritt 4 (geheim)


Jetzt, im vierten, geheimen Schritt unserer Arbeit, können Sie das Ergebnis bewundern und Erfolg haben. Hier ist der Code , der sammelt, worüber wir gerade gesprochen haben.


Das Ergebnis der Anwendung der Lazy Image Loading-Technik

Wenn Sie sich jedoch genauer ansehen, was wir haben, stellt sich heraus, dass Sie hier etwas finden, das nicht sehr gut ist. Um dies zu sehen, habe ich schnell durch die Seite gescrollt und gleichzeitig die Geschwindigkeit der Netzwerkverbindung verlangsamt.


Seitenverhalten, wenn es schnell scrollt und die Netzwerkverbindungsgeschwindigkeit verlangsamt

Da wir das Bild erst laden, nachdem es den Bereich erreicht hat, in dem es bereits sichtbar sein sollte, hat der Benutzer nicht die Möglichkeit, durch die Seite zu scrollen und den vom Bild belegten Bereich und natürlich das Bild selbst zu sehen, bevor er es lädt. Wenn Websites von normalen Computern aus angezeigt werden, die mit dem schnellen Internet verbunden sind, verursacht dies keine Probleme. Viele moderne Benutzer besuchen Websites jedoch von ihren Telefonen aus. Manchmal verwenden sie 3G-Netzwerke oder, noch schlimmer, EDGE-Verbindungen.

Es ist wahr, dass es nicht so schwierig ist, mit diesem Problem umzugehen. Dies kann aufgrund der Tatsache erfolgen, dass die Intersection Observer-API dem Entwickler die Möglichkeit bietet, die Grenzen des .container zu erweitern oder zu verengen (in unserem Fall ist dies das .container Element). Um diese Gelegenheit zu nutzen, fügen Sie einfach eine Codezeile hinzu, in der der Stammcontainer konfiguriert ist:

 rootMargin: "0px 0px 200px 0px" 

rootMargin Eigenschaft rootMargin eine Zeile, deren Struktur den CSS-Regeln entspricht, die zum Konfigurieren des Einrückens von Elementen verwendet werden. In unserem Fall teilen wir dem System mit, dass der untere Rand, der zum Erkennen des Schnittpunkts eines Elements mit einem Container verwendet wird, um 200 Pixel erhöht werden muss. Dies bedeutet, dass der entsprechende Rückruf aufgerufen wird, wenn das Element in einen Bereich fällt, der 200 Pixel unter dem unteren Rand des Stammelements liegt (der Standardwert ist 0).

Hier ist der Code, der diese Technik implementiert.


Verbesserung der Technik des verzögerten Ladens von Bildern

Als Ergebnis stellt sich heraus, dass das Bild in einem Bereich geladen wird, der 200 Pixel unter dem sichtbaren Bereich der Seite liegt, wenn wir die Seite nur zum 4. Element der Liste scrollen.
Nun scheint alles, was benötigt wird, getan zu sein. Aber das ist nicht so.

Bildhöhenproblem


Wenn Sie die obigen GIF-Abbildungen sorgfältig studiert haben, werden Sie möglicherweise feststellen, dass die Bildlaufleiste nach dem Laden des Bildes einen „Sprung“ macht. Glücklicherweise ist dieses Problem leicht zu handhaben. Der Grund dafür ist, dass das Element, das das Bild anzeigt, anfänglich eine Höhe von 0 hat, die sich nach dem Laden des Bildes als 300 Pixel herausstellt. Um das Problem zu beheben, reicht es daher aus, das Element auf eine feste Höhe zu setzen, indem dem Bild das Attribut height={300} hinzugefügt wird.

Über Optimierungsergebnisse


Welche Ergebnisse haben wir bei Walmart erzielt, nachdem wir das verzögerte Laden von Bildern auf dieser Seite angewendet haben? Tatsächlich variieren die spezifischen Ergebnisse stark in Abhängigkeit von vielen Umständen, unter denen wir die Netzwerkverbindungsgeschwindigkeit des Clients, die CDN-Verfügbarkeit, die Anzahl der Bilder auf der Seite und die Regeln zum Erkennen von Schnittpunkten mit dem auf sie angewendeten Stammelement notieren können. Mit anderen Worten, um die Auswirkungen des verzögerten Ladens von Bildern auf Ihr eigenes Projekt zu beurteilen, ist es für Sie am besten, dies selbst zu implementieren und zu überprüfen. Wenn Sie jedoch immer noch daran interessiert sind, was uns das verzögerte Laden von Bildern gebracht hat, finden Sie hier einige Lighthouse-Berichte. Die erste wird vor der Optimierung gebildet, die zweite nach der Optimierung.


Leuchtturmbericht vor der Optimierung erstellt


Leuchtturmbericht nach Optimierung erstellt

Zusammenfassung


Heute haben wir uns eine Technik zur Optimierung von Webseiten durch verzögertes Laden von Bildern angesehen. Wenn die Seiten Ihrer Website voller Bilder sind, ist diese Technik möglicherweise für Sie hilfreich.

Liebe Leser! Wie optimieren Sie Bilder und deren Laden?

Source: https://habr.com/ru/post/de423485/


All Articles