
Vor einiger Zeit interessierte ich mich für die Leistung von Websites, Download-Optimierungen und dergleichen. Und jetzt, als ich wieder ins Habr ging, dachte ich, ich wäre es gewohnt, eine ziemlich schnelle Ressourcenbelastung als gegeben zu betrachten, ohne darüber nachzudenken, wie dies erreicht wurde. Aus diesem Grund habe ich mich entschlossen, Geschäft mit Vergnügen zu verbinden - um zu sehen, wie sich die Leistung von Habr entwickelt und welche technischen Lösungen zur Optimierung entwickelt wurden.
Für diejenigen, die wissen möchten, was getan wurde, damit wir den Inhalt so schnell wie möglich erhalten und wie der Download des Habr aus Argentinien aussieht - bitte unter Katze.
Vorbereitung
Wir benötigen eine neue Version von Chrome / Canary, die im anonymen Modus arbeitet (stellen Sie sicher, dass alle Erweiterungen deaktiviert sind). Außerdem müssen Sie in der Entwicklerkonsole (Developer Tools - F12) auf der Registerkarte "Netzwerk" das Flag "Cache deaktivieren" setzen, da Wir werden nur den ersten Start profilieren, solange sich noch keine Ressourcen im Cache befinden.
Stufe Eins - "Oben"
Das Hauptziel dieses Teils ist es, die Site als Ganzes kennenzulernen, ihre Struktur zu verstehen und herauszufinden, welche spezifischen Ressourcen sie benötigt.
Wir öffnen Entwicklertools, gehen zur Registerkarte "Netzwerk", öffnen die Site und sehen uns ganz unten auf der Registerkarte Statistiken zur Netzwerknutzung an:

Die gesamte Site wurde in 2,02 Sekunden geladen, was einfach großartig aussieht (angesichts der Last von Habr). Das Ereignis DomContentLoaded (im Folgenden einfach DCL) wurde im Allgemeinen in 1,01 Sekunden angezeigt, was sogar noch besser aussieht. Mit all dem stellt die Site 189 Anfragen und lädt 9,6 MB Ressourcen. Dies sagt uns, dass entweder das Habra-Team ein Genie ist (es kann durchaus sein) und der Artikel hier fertiggestellt werden sollte (und sie das Team um Kaffee und Kekse bitten), oder dass ich einen 100-Mbit / s-Kanal und Core I7 habe . Das heißt, Sie müssen der Realität ein wenig näher kommen und zumindest die Kanalbreite begrenzen.
Wir schalten den Fast 3G-Modus ein und schauen noch einmal:

Der DCL verschlechterte sich auf 3,48 Sekunden, was immer noch einigermaßen akzeptabel ist. Aber schließlich wurde die Seite in atheistischen 54,76 Sekunden geladen. Jetzt ist alles logisch - Sie können nicht einfach fast 10 Megabyte herunterladen und herunterladen, wenn Sie eine schwache Verbindung haben. Höchstwahrscheinlich haben die Jungs gute Arbeit geleistet, um uns den Inhalt so schnell wie möglich zu zeigen (dies wird durch die Tatsache belegt, dass DCL auch im Fast3G-Modus schnell genug auftritt), und sie haben alles, was für das Laden nicht kritisch war, im Hintergrund gelassen. Wir werden das etwas später überprüfen und jetzt wollen wir sehen, warum wir so lange geladen haben. Sortieren Sie alle Anfragen nach Ladezeit:

Klickbar
Bilder (Top-7) werden am längsten geladen und eine JavaScript-Datei ist prebid.js. Wenn wir ihre Größe betrachten, können wir annehmen, dass dies genau der Grund für das langsame Laden ist.
Über AnnahmenMit Annahmen müssen Sie äußerst vorsichtig sein. Beispielsweise kann ein langes Laden einer Ressource nicht nur durch die Dateigröße verursacht werden, sondern auch beispielsweise durch Probleme mit DNS, maximale Speicherlast oder einen Cold-Server-Cache. Daher kann eine nicht überprüfte Annahme dazu führen, dass Sie Zeit damit verschwenden, ein Problem zu lösen, das noch nicht einmal existiert.
Wenn wir uns die Statistiken ansehen ( TTFB : 0,610 ms, Last: 40 000 ms), können wir schließen, dass unsere Annahme sehr wahrscheinlich ist. Bewundern wir unsere TOP 1 (png, 1560X780, 24bit):

In der Tat sind Probleme mit Bildern hauptsächlich Probleme unseres Verkehrs mit Ihnen. Bilder (im Gegensatz zu Stilen und Skripten) blockieren das Rendern der Webseite nicht. Trotz des Vorhandenseins solcher Schwergewichte (es kann schlimmer sein, sie haben es gesehen) hat dies fast keinen Einfluss auf die Leistung. Obwohl natürlich eine Optimierung in dieser Richtung (z. B. Transcodierung in jpeg2000 oder webp oder progressives Laden wäre nicht überflüssig).
Über BilderWie ich oben geschrieben habe, blockieren Bilder nicht das Rendern der Seite. Aber sie nutzen unseren Verbindungspool und in http 1.x ist ihre Anzahl begrenzt, und auch bei http 2.x und Chrome ist nicht alles so reibungslos, wie ich gehört habe. Daher besteht auch hier die Möglichkeit, dass ein Bild das Laden eines synchronen Skripts verlangsamt und das Rendern der Seite bereits beendet wird. Darüber hinaus kann das Laden des Bildes auch zu einer Nachzählung des Layouts führen, wodurch das Rendern verlangsamt wird. Wenn wir uns das Habr-Markup ansehen, haben fast alle img-Tags Breite und Höhe. Dadurch entfällt der Reflow, um die Download-Leistung positiv zu beeinflussen. Mehr dazu lesen Sie hier .
Mal sehen, welche anderen Ressourcen der Habr nutzt - wir werden die Typen durchgehen und sie nach Ladezeit sortieren. Beginnen wir mit JavaScript
Javascript
Über JavascriptJavaScript hat verschiedene Probleme mit der Leistung der Website. Erstens (jeder weiß das schon lange) blockiert synchrones js das weitere Rendern von Seiten. Das heißt, Bis wir unser JavaScript erhalten und ausführen, wartet der Browser (eigentlich nicht ganz, der Browser, insbesondere Chrome, kann optimieren, aber dies ist eine andere Geschichte) und rendert keinen weiteren Inhalt. Mit synchronen Skripten im Kopf verschieben wir den Moment, in dem der Benutzer mindestens etwas sieht (sogar Text). Daher versucht jeder, Js am Ende der Seite zu werfen oder sie sogar asynchron zu machen. Dies funktioniert, löst aber nicht das zweite Problem, das uns die Tatsache bringt, dass JavaScript immer noch eine Skriptsprache ist. Daher reicht der Browser nicht aus, um ihn nur herunterzuladen - er muss auch "verstanden" werden. Und hier stellt sich heraus, dass dies ein Problem ist, da schwache Prozessoren (z. B. in billigen Telefonen oder Netbooks oder sogar guten Laptops im eingeschränkten Leistungsmodus) dies langsam tun und den Haupt-Thread blockieren! Im Folgenden finden Sie ein Beispiel dafür, wie ein asynchrones Werbeskript in den kritischen Bereich des Habr-Renderings eingedrungen ist und zwar ein wenig, aber dennoch die Leistung beeinträchtigt hat. Wenn jemand interessiert ist, gibt es einen sehr (sehr, sehr) guten Artikel zu diesem Thema.
Habr-Skripte laden viel - 1,1 MB (und dies ist bereits in komprimierter Form) für 40 Anfragen. Dies ist ehrlich gesagt wichtig, es kommt immer noch auf uns zurück und wir müssen etwas dagegen tun. Sortieren Sie unsere Skripte "nach dem Wasserfall". Unsere Aufgabe ist es, Skripte zu finden, die VOR der blauen Linie geladen wurden, da sie (höchstwahrscheinlich) verhindern, dass wir die Site so schnell wie möglich rendern.

Klickbar
Wir öffnen das HTML, das Habr uns gegeben hat (es ist wichtig, die Antwort zu lesen, da das endgültige HTML anders aussehen wird) und gehen die Liste durch. Wie Sie sehen können, werden jQuery, raven.js, Advertise.js und adriver.js synchron direkt vom Head-Tag geladen (d. H. Sie blockieren überhaupt alles). Gpt und Publisher werden vom Kopf geladen, aber bereits asynchron (d. H. Sie blockieren nichts, der Browser rendert die Seite weiter, während sie geladen werden). Vendors, Main und Math, Checklogin werden am Ende geladen, aber synchron (d. H. Der Text ist bereits vorhanden, wir können ihn lesen, aber die DCL wird erst angezeigt, wenn sie geladen werden). Der Rest erscheint nicht in der ersten Antwort - sie werden dynamisch hinzugefügt, aber dies ist ein anderes Thema.
Wir haben also Skripte gefunden, die sich irgendwie darauf auswirken, wie schnell wir den Text auf der Seite sehen. Dies sind die ersten Kandidaten für eine Optimierung. Idealerweise sollten sie asynchron oder so niedrig wie möglich platziert werden, damit der Browser Inhalte für uns rendern kann. Das Ideal ist jedoch nicht erreichbar, da es höchstwahrscheinlich andere Skripte auf der Site gibt, die von derselben jQuery abhängen. Der Wunsch, Raven so schnell wie möglich herunterzuladen - eine Bibliothek zum Verfolgen verschiedener Fehler, die auf dem Client auftreten - kann ebenfalls verstanden werden. Advertise.js und adriver.js sind jedoch bereits echte Kandidaten, um zumindest die Seite nach unten zu bewegen, und maximal auch im asynchronen Modus. Eine ähnliche Geschichte mit gpt und Publisher. Ja, sie werden asynchron geladen, aber sie können (und werden) uns beim Laden stören. Daher können auch sie ganz unten auf der Seite gesendet werden. Darüber hinaus können Sie versuchen, die Attribute " Ressourcenhinweise" - "Preload / Prefetch / DNS-Prefetch" zu verwenden, um dem Browser mitzuteilen, was im Voraus geladen werden soll. Übrigens rate ich Ihnen, über Ressourcenhinweise zu lesen - ein sehr interessantes Tool, wenn auch mit begrenzter (bisheriger) Unterstützung.
Sortieren Sie nun die Liste nach Dateigröße:

https://github.com/Drag13/articles/blob/habrformance/habrformance/scripts.PNG
Wir sehen ein Skript, das zweimal geladen wird (Pubads). Wir stellen außerdem fest, dass prebid.js aus dem Not-for-Prod-Ordner geladen wird

Um unser Gewissen zu klären, überprüfen wir, ob alle Skripte minimiert sind. Plötzlich wurden die Skripte check-login.js und adriver.js nicht minimiert. Besonders zufrieden mit dem Inhalt des letzteren:

Und mit Skripten können Sie vorübergehend beenden.
Stile
Über StileBei Stilen ist auch nicht alles so einfach. Erstens blockiert das synchrone Laden von Stilen auch den Hauptthread (obwohl sie schnell und schneller als JavaScript analysiert werden). Und zweitens ist alles etwas komplizierter. Warum benötigt der Browser CSS? CSSOM erstellen . Was kann JavaScript mit CSS tun? Das ist richtig - ändern. Und was passiert, wenn CSSOM noch nicht erstellt wurde und js dort bereits versucht, etwas zu ändern? Die Antwort ist wer weiß. Daher verzögert der Browser die Ausführung von JavaScript, bis die CSSOM berechnet ist. Wie in einem anderen sehr nützlichen Artikel richtig geschrieben - kein CSS = kein JavaScript. Daher blockiert das Laden von CSS die JS-Ausführung.
Hier sind die Stile, die Habr lädt:

Klickbar
Wie Sie sehen können, gibt es nur drei davon, wobei der zweite und der dritte in einem separaten Frame geladen sind. Daher ignorieren wir sie. Der erste Satz von Stilen ist jedoch für die gesamte Site von entscheidender Bedeutung. Und wir haben es sehr lange heruntergeladen. Warum? Erstens haben sie lange auf eine Antwort vom Server gewartet (TTFB 570 ms, wir werden im dritten Abschnitt darauf zurückkommen), und zweitens wurden 713 ms für eine lange Zeit geladen. Was kann man hier machen? Die erste und einfachste Möglichkeit besteht darin, das Preload-Attribut hinzuzufügen. Dadurch wird der Browser aufgefordert, CSS so früh wie möglich zu laden. Die zweite Möglichkeit besteht darin, kritisches CSS hervorzuheben und direkt in die Webseite einzubetten und den Rest synchron (oder sogar asynchron) zu laden. Dies führt zu einer Vergrößerung der Seite (aber sie ist bereits nicht klein und + 5 KB verderben nichts) und einer möglichen Neugestaltung des Layouts (Zeitverlust), aber Sie können es versuchen.
Ich werde nicht einmal Schriftarten anzeigen. Es ist alleine da, obwohl es aus irgendeinem Grund direkt vom Habr-Server anstelle des CDN geladen wird (und höchstwahrscheinlich aus einem Grund). Aber ich werde mich dafür bedanken, dass es nur eine Schriftart gibt.
Hierbei kann der Übersichtsteil der Site-Analyse als abgeschlossen betrachtet werden. Zeit, tiefer zu gehen.
Stufe zwei - "Manueller Modus"
In der letzten Phase haben wir gesehen, dass Habr lädt. Jetzt werden wir sehen, wie dies gerendert wird.
Wechseln Sie zur Registerkarte Profilerstellung. Wir überprüfen, was Slow3g verlangsamt (dann ohne Einschränkungen erneut ausführen) und führen es aus. Zunächst interessieren wir uns für alles, was vor dem First Contentful Paint (FCP) -Ereignis passiert, und für alle Fälle für DCL. Wir wählen den Bereich vom Beginn des Ladens in FCP aus und sehen uns das endgültige Diagramm an.

Alles geht ziemlich schnell - 2,161 Sekunden vor FCP (es war schneller, aber anscheinend hatte sich etwas geändert), aber wie Sie sehen können, war der Browser die meiste Zeit im Leerlauf. Die Nutzlast dauerte nur 14% der Zeit (ca. 310 ms). Im Idealfall wird der Hauptbrowser-Thread kontinuierlich ausgeführt. Beim Parsen von HTML, CSS und JS wird JS ausgeführt. Und hier - nichts. Warum? Weil der Browser einfach nichts zu tun hatte. Erinnerst du dich, dass wir den Verkehr reduziert haben? Der Browser hat Anfragen gesendet und wartet nun nur darauf, dass diese abgeschlossen werden. Wenn wir das Diagramm der Netzwerkprozesse (das oberste) öffnen, wird alles sofort klar.

Klickbar
Im Jahr 2029 sah der Browser main.bundle.css, schickte eine Anfrage, um sie zu erhalten, und begann zu warten. Zu diesem Zeitpunkt stellte der Prescanner (Smart Chrome, es kann vorauslaufen) fest, dass sich unten synchrone Skripte befinden, und ohne auf das Eintreffen von CSS zu warten, schickte er eine Anfrage nach Skripten. Dann werben und adriver laden (aber wir erinnern uns, dass CSSOM nicht erstellt wird, Sie JS jedoch nicht berühren können), sodass der Browser sie ignorierte. Danach wurden gpt und raven geladen, aber das CSS wurde noch geladen, sodass sie ebenfalls ignoriert wurden. Schließlich wurde CSS geladen, das der Browser in 12 ms analysierte und sofort das in die Seite eingebettete JS analysierte. Dann schlief der Browser nach fast 150 ms wieder ein und wartete auf jQuery.min.js. Und danach habe ich bereits ernsthaft angefangen zu arbeiten - ich habe die geladene jQuery (20 ms) herausgefunden, raven.js (4 ms) analysiert, fast die gesamte Seite (36 ms) analysiert, die Stile (28 ms) nachgezählt, das Layout berechnet (78 ms + 8 ms) und Schließlich haben wir für ~ 6 ms die Seite gemalt. Hier haben wir FCP. Als nächstes analysieren wir die Seite, analysieren die Skripte - Hallo an niemanden (publishertag.js, gpt.js, der vor DCL in den Hauptthread gelangt ist), spielten ein wenig mit Stilen herum (was aufgrund der Neuberechnung des Layouts einen leichten Zeitverlust verursachte) und warteten auf Anbieter. bundle.js. Um auf die Anbieter zu warten, haben wir fast 1100 ms im Leerlauf verbracht. Parallel dazu haben wir auch main.bundle.js geladen (die übrigens schneller gebootet haben), also ist nicht alles so schlecht. Dann ging alles wieder gut. Wir haben die Anbieter analysiert, das Hauptpaket analysiert, Math.Jax analysiert und schließlich die Seite analysiert und DCL erhalten. Zwar funktionierte genau dort eine Art Handler, der auf meinem I7 den Hauptthread bei 80 ms stoppte (d. H. Die Site schien bei 80 ms einzufrieren). Jetzt haben wir das fast nicht bemerkt, aber auf einem schwachen Prozessor kann es theoretisch auffallen. Wenn Sie dies nach dem Rendern des Inhalts sehen, ist dies eine Gelegenheit, JS zu überprüfen.
Was soll ich sagen Wieder trotz der Tatsache, dass es ziemlich gut aussieht. Die Hauptprobleme wurden uns geliefert:
- Ein großer einfacher Browser (auch aufgrund des künstlichen Ungleichgewichts zwischen der Rechenleistung des Computers und der Kanalbreite, aber dies ist auch ein durchaus gültiges Szenario)
- Langes CSS-Laden, das die Arbeit mit kritischen js verzögerte
- Synchrones Laden von jQuery, Anbietern und Hauptpaketen, wodurch das Auftreten von Inhalten gestoppt wurde.
Was wir damit machen können, haben wir bereits besprochen:
- Versuchen Sie, das Preload-Attribut für CSS und möglicherweise JS hinzuzufügen
- CSS reduzieren oder inline
- Versuchen Sie im Allgemeinen, Skripte aus dem synchronen Laden herauszuwerfen (zumindest einige).
Wiederholen wir nun dasselbe ohne Einschränkungen der Kanalbreite. Das Bild ist schon viel besser: 0,452 Sekunden zu FMP, dem einfachsten von allen! 13 ms. DCL - 953 ms, einfach 15 ms. So sieht mein Traum-Download aus. Genau das ist passiert, weil ich einen neuen Tab geöffnet und das Caching nicht entfernt habe. Versuchen wir dasselbe, aber ohne Cache:

Alles ist auch ganz gut, FCP / FMP - 1689, Nutzlast 45%. Übrigens ist es auch schlecht, die Last auf 100% einzustellen, da schwächere Maschinen überlastet werden. Es ist also besser, eine Reserve für Ausfallzeiten zu haben. Aber hier wurde unerwartet viel Zeit für das Rendern aufgewendet - 400 ms für FMP. Davon entfielen 200 ms auf die Neuberechnung von Stilen und die Neuberechnung des Layouts.
Übrigens ein weiterer interessanter Punkt. Erinnern Sie sich an die Anzeigenskripte - gpt.js und publishertag.js, die im ersten Teil erwähnt wurden? Jetzt können Sie sehen, dass sie trotz ihrer Asynchronität (wenn auch ein wenig) unsere Statistiken ruinieren konnten. Dies geschah, weil die Ausführung von asynchronen Skripten entsprechend der Bereitschaft der Skripte selbst erfolgt. Das heißt, Dies kann jederzeit geschehen, auch vor FCP / DCL, was 3309 geschah.
Also haben wir die manuelle Demontage durchgeführt. Es ist Zeit, die Automatisierung aufzudecken.
Stufe drei - „Wir mussten damit anfangen“
Über die KollektivfarmIch denke, jeder versteht, dass diese Studie sehr willkürlich ist. Zumindest, weil die ganze Zeit, während ich neue Artikel testete, die Last auf dem Server und die Last auf den Netzwerk-Backbones geändert wurden. Auf eine gute Weise müssen Sie einen dedizierten Server bereitstellen, auf dem niemand etwas schreibt, die relevante Last mit relevanten Verzögerungen emuliert und erst dann ein Profil erstellt. Andernfalls können Sie einige Annahmen treffen (z. B. über die Notwendigkeit, ein Preload-Attribut in CSS hinzuzufügen), es hinzufügen, für die Produktion bereitstellen, und dann stellt sich heraus, dass die Last während des Tests stark gestiegen ist und der Server uns 500 ms später den gleichen Stil gegeben hat. Und es stellt sich heraus, dass die Vorspannung schlecht ist - es hat alles nur noch schlimmer gemacht. Und der Autor ist der letzte Rettich überhaupt. Darüber hinaus macht die manuelle Profilerstellung (wie im zweiten Teil) wenig Sinn, bis Sie alle automatischen Werkzeuge entfernt und die dort gefundenen Probleme gelöst haben, da sich das Bild nach Ihren ersten Änderungen ändert.
Daher benötigen wir vor allen Experimenten die stabilste Umgebung. Diesmal. Das zweite - Sie sollten niemals von Anfang an tief gehen (zum Beispiel in die Profilerstellung). Starten Sie zuerst die automatischen Werkzeuge und lassen Sie sie für Sie arbeiten. Sammeln Sie Berichte und sehen Sie, was in kürzester Zeit so gut wie möglich getan werden kann. Versuche es zu tun. Wenn möglich, haben Sie möglicherweise bereits genug. Zum Beispiel wiegt Ihr css.bundle 100 KB, aber in Wirklichkeit benötigen Sie 45 KB (übrigens die reale Situation: Sie haben den gesamten Bootstrap genommen, aber nur das Raster wurde benötigt). Sie reduzierten die Größe der Stile und gewannen praktisch umsonst eine halbe Sekunde. Das sind zwei. Immer überprüfen. Es scheint, dass Stile inline sind, alles sollte besser werden, aber es wird schlechter. Und warum? Und weil in den Stilen von 50 KB Base64-Bildern und unserer Seite gerade 200 KB Ressourcen geladen wurden. Denken Sie daran, dass es keine Silberkugel und universelle Skripte gibt. Das sind drei. Und das letzte, auch wenn es dem vorherigen Satz widerspricht. Wenn Sie keine komplizierte Site haben, überwachen Sie einfach TTFB (Serverprobleme), die Größe der heruntergeladenen Ressourcen (Hallo zu den Logos für 2 MB) und gewähren Sie niemandem Zugriff auf Google Tag Manager. Höchstwahrscheinlich wird dies völlig ausreichen.
Wir werden nicht weit gehen. Öffnen Sie in denselben Entwicklertools die Registerkarte "Überwachung" und starten Sie LightHouse (LH) mit den folgenden Einstellungen: Desktop, nur Leistung, keine Drosselung, Speicherplatz löschen. Nachdem wir ein wenig gewartet haben (verlassen Sie nicht die Seite, auf der das Audit durchgeführt wird, und machen Sie nichts besseres), erhalten wir fantastische Zahlen (auch wenn der Cache deaktiviert ist).

Es scheint mir sogar, dass sie speziell auf diese Figuren zugeschnitten waren.
LH beschwert sich jedoch immer noch über:
- Veraltetes Bildformat (empfiehlt die Verwendung von webp, jpeg2000 usw.)
- DOM node – : 2533, 1500.
- — 23
- document.write
. (), DOM — node (-), ( ), document.write- writer ( - )
( ) . , , , . , , . CSS, — , , JavaScript. , , . .
, fast3g , , ( I7, celeron):

( FCP 3500 ms, FMP 5.7):
- , . LH next-gen , , , 11
- . adriver.js advertise.js 50 , .
- CSS , 5kb 45kb.
- main thread. JavaScript — (8.5 script evaluation 2186 ms raven.js). ?
? . - . :
, , (, raven.js).
, , — webpagetest.org
— , , . — , . , . , , . , , , — -.
https://habr.com ( ru/en ).

( , )
. ( ) DNS (500 ms ), , ssl . , 1150 ms c ( ). , ( habrastorage).
main.bundle.css. , dr.habracdn.net , dns lookup — 36 ms ( 400 ms). SSL negotiation 606 ms, TTFB 601 ms, . . DCL — 4100 ms , .
image analysis , , . - PNG 1.4, webp + downscaling ( , ) — 17.7 KB. , , png 154. . , :
- ( , , .. ).
- . , .
- TTFB (webpagetest F ) —
- , ( )
Schlussfolgerungen
. :
:
- TTFB 500 ms ( dns, ssl initial connection)
- habrastorage
:
, , . , , . , SPA, , JS — . . //,
Nützliche Links
PS. ( ) . , .1, .2, .3 .