Wie Early Hints und Priority Hints Ihre Websites beschleunigen können
Websites werden immer noch zu langsam geladen. Während der kritischsten Phase des Seitenladevorgangs befindet sich Ihre Verbindung oft fast vollständig im Leerlauf. Eine neue Technologie von Fastly Entwickler Kazuho Oku bietet das Potenzial, diese entscheidenden ersten paar Sekunden besser zu nutzen.
Haben Sie schon einmal auf Ihrem Smartphone eine Website geöffnet und dann 10 Sekunden lang auf eine Seite ohne Text gestarrt? Niemand schaut gerne auf einen leeren Bildschirm, während die nutzerdefinierte Schriftart einer Website geladen wird. Es wäre also sinnvoll, wenn wenn die Ladezeiten solch kritischer Seitenbestandteile so kurz wie möglich wären. Als Teil der Lösung für dieses Problem war Link rel=preload gedacht. Der Browser parst die HTTP-Header einer Seite, bevor er mit dem Lesen des Inhalts beginnt. Dies ist also der ideale Zeitpunkt, um ihm mitzuteilen, dass er mit dem Download von Assets beginnen soll, die wir definitiv brauchen.
Das Internet ist von Natur aus langsam
Schauen wir uns an, was passiert, wenn Sie die Preload-Funktion nicht verwenden. Der Browser kann erst dann mit dem Laden von Ressourcen beginnen, wenn er weiß, dass er sie benötigt. Dies geschieht am schnellsten bei Ressourcen, die schon beim ersten Parsen des Dokuments aus dem HTML-Code hervorgehen, darunter <script>
, <link rel=stylesheet>
und <img>
.
Bei denjenigen Website-Bestandteilen, die erst aus der Renderstruktur hervorgehen, dauert der Download länger. Die Renderstruktur verrät Ihnen, dass Sie eine nutzerdefinierte Schriftart benötigen. Dazu müssen Sie aber zuerst das Stylesheet laden, es parsen und das CSS-Objektmodell erstellen.
Noch langsamer werden Ressourcen geladen, die Sie dem Dokument über JavaScript Loader hinzufügen, die durch Ereignisse wie DOMContentLoaded
ausgelöst werden. Unterm Strich entsteht beim Laden einer Website also eine unlogische und optimierungsbedürftige Wasserfallstruktur. So kommt es zu einer Menge Leerlauf im Netzwerk und Ressourcen werden entweder früher als nötig oder viel zu spät geladen:
Link rel=preload ist ein guter erster Schritt
In den letzten Jahren ist es uns gelungen, durch die Verwendung von Link rel=preload eine bessere Performance zu erzielen. Hier einige Beispiele:
Link: </resources/fonts/myfont.woff>; rel=preload; as=font; crossorigin
Link: </resources/css/something.css>; rel=preload; as=style
Link: </resources/js/main.js>; rel=preload; as=script
Mit diesen Einstellungen kann der Browser mit dem Laden der Ressourcen beginnen, sobald die Header empfangen werden und bevor er den HTML-Body parst:
Dies ist eine erhebliche Verbesserung, insbesondere für umfangreiche Seiten und für kritische Ressourcen, die sonst erst später geladen werden (damit meine ich vor allem Schriftarten, aber auch Dateien, die zum Booten von JavaScript Anwendungen benötigt werden, können kritische Ressourcen sein).
Es gibt aber noch jede Menge Luft nach oben. Zwischen dem Moment, in dem der Browser das Senden der Anfrage beendet hat, und dem Empfang der ersten Bytes der Antwort ist er absolut untätig (siehe den großen grünen Bereich im obigen Diagramm).
Nutzung der „Server-Denkzeit“ mit Early Hints
Der Server hingegen ist sehr beschäftigt. Er generiert die Antwort und entscheidet über ihren Erfolg oder Misserfolg. Nach einigen Datenbankzugriffen, API Calls, Authentifizierungen und so weiter, könnte die Antwort letztendlich ein 404-Fehler sein.
Manchmal ist die „Server-Denkzeit“ geringer als die Latenzzeit des Netzwerks, sie kann aber auch wesentlich länger sein. Wir sollten uns allerdings dessen bewusst sein, dass die beiden sich nicht überschneiden. Während der Server „nachdenkt,“ werden keine Daten an den Client gesendet.
Interessanterweise sind aber schon bevor Sie an die Generierung einer Antwort denken, einige der Stile und Schriftarten bekannt, die zum Rendern der Seite geladen werden müssen. Schließlich verwenden Ihre Fehlerseiten im Allgemeinen dasselbe Branding und Design wie Ihre normalen Seiten. Wäre es nicht großartig, wenn Sie diese Header mit Link: rel=preload
senden könnten, bevor der Server nachdenkt? Gute Neuigkeiten: Zu diesem Zweck gibt es Early Hints, die in RFC8297, einem Produkt der HTTP Working Group spezifiziert wurden, das von meinem Fastly Kollegen Kazuho Oku entwickelt wurde. Sehen Sie hier, wie Sie mehrere Statuszeilen in einer einzigen Antwort erfassen können:
HTTP/1.1 103 Early Hints
Link: <some-font-face.woff2>; rel="preload"; as="font"; crossorigin
Link: <main-styles.css>; rel="preload"; as="style"
HTTP/1.1 404 Not Found
Date: Fri, 26 May 2.017 10:02:11 GMT
Content-Length: 1.234
Content-Type: text/html; charset=utf-8
Link: <some-font-face.woff2>; rel="preload"; as="font"; crossorigin
Link: <main-styles.css>; rel="preload"; as="style"
Der Server kann den ersten, sogenannten „informativen“ Antwortstatus schreiben, sobald er die Anfrage erhält, und ihn an das Netzwerk weiterleiten. Anschließend kann er entscheiden, wie die eigentliche Antwort lauten wird, und diese generieren. In der Zwischenzeit können Sie im Browser schon zu einem viel früheren Zeitpunkt mit dem Preload beginnen:
Dazu sind einige Änderungen an der Funktionsweise von Browsern, Servern und CDNs notwendig. Manche Browseranbieter haben Vorbehalte wegen der Schwierigkeiten bei der Implementierung geäußert, sodass es noch unklar ist, wann diese Lösung verfügbar sein wird. Die Fortschritte können Sie in den öffentlichen Trackern für Chrome und Firefox verfolgen.
Wir hoffen, dass es bald möglich sein wird, Early Hints direkt von Fastly aus zu senden, während Sie die Anfrage weiterhin an den Origin-Server schicken. Wir haben noch nicht entschieden, wie wir das in VCL umsetzen. Lassen Sie uns also wissen, wie Sie es gerne hätten!
Und was ist mit HTTP/2 Server Push?
Mit HTTP/2 erhalten Sie Zugang zu einer neuen Technologie namens Server Push, die dasselbe Problem zu lösen scheint wie das Senden von Link rel=preload in einer Early Hints Antwort. Push funktioniert zwar (und Sie können mit Fastly sogar nutzerdefinierte Pushs von der Edge aus erzeugen), aber es gibt auch gute Gründe, warum sich manche Entwickler dagegen entscheiden:
Der Server weiß nicht, ob der Client bereits über die Ressource verfügt, sodass er sie oft pusht, obwohl er sie gar nicht benötigt. Aufgrund von Pufferung und Latenzen im Netzwerk hat der Client in der Regel keine Möglichkeit, den Push abzubrechen, bevor er den gesamten Inhalt erhalten hat. (Es gibt allerdings eine mögliche Lösung für dieses Problem in Form des vorgeschlagenen Cache Digest-Headers, an dem Kazuho zusammen mit Yoav Weiss von Akamai arbeitet).
Ressourcen, die gepusht werden, sind verbindungsgebunden. Man kann also leicht eine Ressource pushen, die ein Client am Ende nicht nutzen kann, weil er versucht, sie über eine andere Verbindung abzurufen. Die Clients müssen möglicherweise eine andere Verbindung verwenden, weil die Ressource auf einem anderen Origin-Server liegt, der nicht dasselbe TLS-Zertifikat hat, oder weil sie in einem anderen Anmeldemodus abgerufen wird.
H2 Push ist nicht sehr einheitlich implementiert, wenn man die großen Browseranbieter vergleicht. Daher ist es schwer vorherzusagen, ob es in Ihrem speziellen Anwendungsfall funktionieren wird oder nicht.
Abgesehen davon bieten Early Hints und Server Push unterschiedliche Vorteile. Early Hints ermöglicht eine effizientere Nutzung des Netzwerks im Austausch für einen zusätzlichen Round Trip. Wenn Sie mit einer kurzen Netzwerklatenz und einer langen Server-Denkzeit rechnen, sind Early Hints wohl die beste Lösung.
Aber das ist nicht immer der Fall. Seien wir optimistisch und stellen wir uns vor, dass Menschen bald auf dem Mars sein werden. Sie werden mit einer Latenzzeit von 20–45 Minuten pro Round Trip im Internet surfen, sodass der zusätzliche Round Trip besonders beschwerlich und die Server-Denkzeit im Vergleich dazu unbedeutend ist. Hier ist der Server-Push leicht im Vorteil. Aber wenn wir jemals vom Mars aus im Internet surfen, ist es wahrscheinlicher, dass wir eine Art Paket herunterladen, wie es die aktuellen Webpakete und die Vorschläge zum signierten Austausch vorsehen.
Nebeneffekt: schnelleres Request Collapsing
Der primäre Anwendungsfall für Early Hints ist zwar der Browser, aber möglicherweise gibt es auch einen interessanten Vorteil für CDNs. Wenn Fastly viele Anfragen für dieselbe Ressource zur gleichen Zeit erhält, senden wir normalerweise nur eine davon an den Origin-Server und stellen die anderen in eine Warteschlange, ein Prozess, der als Request Collapsing bekannt ist. Wenn die Antwort, die wir schließlich vom Origin-Server zurückbekommen, Cache-Control: private
enthält, müssen wir alle Anfragen aus der Warteschlange nehmen und sie einzeln an den Origin-Server senden, da wir diese eine Antwort nicht für mehrere Anfragen verwenden dürfen.
Wir können diese Entscheidung erst treffen, wenn die Antwort auf die erste Anfrage eingegangen ist. Wenn wir jedoch Early Hints unterstützen und der Server eine Early Hints Antwort mit dem Cache-Control-Header ausgibt, wissen wir möglicherweise schon viel früher, dass die Warteschlange nicht zu einer einzigen Anfrage zusammengefasst werden kann, und können stattdessen alle Anfragen in der Warteschlange sofort an den Origin-Server senden.
Priorisierung von weniger kritischen Inhalten mit Priority Hints
Early Hints sind eine großartige Möglichkeit, Zugang zu einigen der wertvollsten Ressourcen in der Wasserfallstruktur zu erhalten: Wenn sich das Netzwerk im Leerlauf befindet, wartet der Nutzer. Es gibt nur eine einzige Anfrage und der Bildschirm bleibt leer. Aber sobald das HTML geladen und die Seite geparst ist, explodiert die Anzahl der Ressourcen, die abgerufen werden müssen. Jetzt kommt es nicht mehr darauf an, die Dinge so schnell wie möglich, sondern in der richtigen Reihenfolge zu laden. Browser verwenden ein komplexes Gewirr von Heuristiken, um die Ladepriorität selbst zu bestimmen. Wenn Sie sich über ihr Urteil hinwegsetzen möchten, können Sie das in Zukunft vielleicht mit Priority Hints tun:
<script src="main.js" async importance="high"></script>
<script src="non-critical-1.js" async importance="low"></script>
Mit diesem neuen Prioritätsattribut können Entwickler die Reihenfolge steuern, in der die Ressourcen heruntergeladen werden, wenn das Traffic-Aufkommen im Netz gerade sehr hoch ist. Auch können weniger wichtige Ressourcen vom Browser zurückgestellt werden, bis die CPU und das Netzwerk im Leerlauf sind – oder aus anderen Gründen, die das Gerät selbst bestimmt.
Wie kann ich Early Hints und Priority Hints nutzen?
Weder Priority Hints noch Early Hints sind derzeit bei Fastly verfügbar. H2O, der von Fastly genutzte und unterstützte HTTP/2-Server, hat bereits mit der Unterstützung von Early Hints begonnen (siehe PRs 1727 und 1767). Es besteht auch die Absicht Priority Hints in Chrome zu implementieren. Darüber hinaus verfolgt das Chrome Team aktiv 1xx-Antworten, um Nutzungsdaten zu erhalten. In der Zwischenzeit kann es nicht schaden, Early Hints zu versenden, wenn Sie der Entwicklung einen Schritt voraus sein wollen!