HTTP / 2 versprach, das Web erheblich zu beschleunigen, und Cloudflare stellte vor langer Zeit den HTTP / 2-Zugriff für alle Clients bereit. Ein Merkmal von HTTP / 2, die Priorisierung, entsprach jedoch nicht den Erwartungen. Nicht weil es grundlegend kaputt ist, sondern wegen der Implementierung in Browsern.
Heute schlägt Cloudflare vor, die Priorisierung von HTTP / 2 zu ändern, um unseren Servern die Kontrolle über Priorisierungsentscheidungen zu geben, die das Internet wirklich beschleunigen.
In der Vergangenheit war es der Browser, der kontrollierte, wie und wann Webinhalte heruntergeladen werden sollten. Heute nehmen wir für alle bezahlten Pläne radikale Änderungen an diesem Modell vor. Sie übertragen die Kontrolle direkt an den Websitebesitzer. Auf der Registerkarte "Geschwindigkeit" im Cloudflare-Dashboard können Clients die "Erweiterte HTTP / 2-Priorisierung" aktivieren: Sie überschreibt die Standardbrowsereinstellungen für ein verbessertes Planungsschema, das den Zugriff für Besucher erheblich beschleunigt (in einigen Fällen konnten wir eine Steigerung von 50% feststellen). Mit Cloudflare-Mitarbeitern können Websitebesitzer noch weiter gehen und die Einstellungen vollständig an ihre spezifischen Anforderungen anpassen.
Aktuelle Situation
Webseiten bestehen aus
Dutzenden (manchmal Hunderten) einzelner Ressourcen, die vom Browser heruntergeladen und für den endgültig angezeigten Inhalt gesammelt werden. Dies umfasst den sichtbaren Inhalt, mit dem der Benutzer interagiert (HTML, CSS, Bilder), sowie die Anwendungslogik (JavaScript) für die Website selbst, Werbe-, Analyse- und Marketing-Tracking-Beacons. Aus Sicht des Benutzers ist die Reihenfolge, in der diese Ressourcen geladen werden, sehr wichtig: Dies wirkt sich auf die Zeit aus, zu der er den Inhalt sieht und mit der Seite interagieren kann.
Ein Browser ist in der Tat eine HTML-Verarbeitungs-Engine, die ein HTML-Dokument durchläuft und die Anweisungen der Reihe nach befolgt: Von Anfang bis Ende HTML, Erstellen der Seite während des Verschiebens. Stylesheet-Links (CSS) teilen dem Browser mit, wie der Inhalt der Seite gestaltet werden soll, und der Browser verzögert die Anzeige des Inhalts, bis das Stylesheet geladen wird. Skripte auf der Seite können sich unterschiedlich verhalten. Wenn das Skript als "asynchron" oder "ausstehend" markiert ist, kann der Browser das Dokument weiter verarbeiten und das Skript einfach ausführen, sobald es verfügbar ist. Wenn das Skript nicht als asynchron oder verzögert markiert ist,
MUSS der Browser die Verarbeitung des Dokuments beenden, bis das Skript geladen und ausgeführt wird. Solche Skripte werden als "Blockieren" bezeichnet, da sie den Browser daran hindern, das Dokument weiter zu verarbeiten.
Das HTML-Dokument ist in zwei Teile unterteilt. Der Titel des <head> -Dokuments steht am Anfang und enthält Stylesheets, Skripte und andere Browseranweisungen, die zum Anzeigen des Inhalts erforderlich sind. Nachdem die Überschrift der Hauptteil des Dokuments <body> ist, enthält sie den tatsächlichen Inhalt, der im Browserfenster angezeigt wird (obwohl sich auch Skripte und Stylesheets im Hauptteil befinden können). Bis der Browser den Dokumententext erreicht, hat der Benutzer nichts anzuzeigen und die Seite bleibt leer. Daher ist es wichtig, den Header so schnell wie möglich zu verarbeiten. Wenn Sie an Details interessiert sind, finden Sie auf der
HTML5 Rocks- Website ein
großartiges Tutorial zur Funktionsweise von Browsern.
Der Browser ist normalerweise für die Reihenfolge verantwortlich, in der die verschiedenen Ressourcen geladen werden, die zum Erstellen der Seite und zum weiteren Verarbeiten des Dokuments erforderlich sind. In HTTP / 1.x gibt es Einschränkungen, wie viele Objekte der Browser gleichzeitig von einem Server anfordern kann (normalerweise 6 Verbindungen und jeweils nur eine Ressource pro Verbindung), sodass die Reihenfolge der Anforderungen vom Browser streng kontrolliert wird. In HTTP / 2 ist die Situation völlig anders. Der Browser kann alle Ressourcen gleichzeitig anfordern (zumindest sobald er davon erfährt) und stellt dem Server detaillierte Anweisungen zur Bereitstellung dieser Ressourcen zur Verfügung.
Optimale Reihenfolge beim Laden von Ressourcen
In den meisten Fällen gibt es eine optimale Reihenfolge im Seitenladezyklus, die die Verfügbarkeit der Seite für den Benutzer maximiert (und der Unterschied zwischen der optimalen und der nicht optimalen Ladereihenfolge kann 50% oder mehr erreichen).
Wie oben beschrieben, wird der Browser, bevor er Inhalte anzeigen kann, durch CSS und JavaScript im Abschnitt
<head>
blockiert. In dieser Phase ist es rentabler, 100% des Kanals zum Laden blockierender Ressourcen zu verwenden, als sie in der Reihenfolge zu laden, wie sie im HTML-Code geschrieben sind. Auf diese Weise kann der Browser jedes Element analysieren und ausführen, während die nächste blockierende Ressource geladen wird, wodurch eine optimale Pipeline erstellt wird.

Die Ladezeit des Skripts für das parallele oder sequentielle Laden unterscheidet sich nicht, aber für das sequentielle Laden kann das erste Skript während des zweiten Ladens verarbeitet und ausgeführt werden.
Nach dem Laden blockierender Ressourcen wird die Situation etwas interessanter. Hier kann die optimale Auslastung von einer bestimmten Website oder sogar von Geschäftsprioritäten abhängen (Auswahl von benutzergenerierten Inhalten oder Werbung oder Analysen usw.). Ein separates Problem mit Schriftarten, da der Browser die gewünschten Schriftarten erkennt, nachdem er das Stylesheet auf den angezeigten Inhalt angewendet hat. Wenn der Browser von der Schriftart erfährt, muss daher Text angezeigt werden, der bereits für die Anzeige auf dem Bildschirm bereit ist. Verzögerungen beim Laden der Schrift führen dazu, dass kein Text auf dem Bildschirm angezeigt wird (oder der Text in der falschen Schrift angezeigt wird).
In der Regel müssen einige Kompromisse berücksichtigt werden:
- Benutzerdefinierte Schriftarten und Bilder im sichtbaren Teil der Seite (Ansichtsfenster) sollten so schnell wie möglich geladen werden. Sie wirken sich direkt auf die visuelle Erfahrung des Benutzers beim Laden der Seite aus.
- Nicht blockierendes JavaScript sollte in Bezug auf andere JavaScript-Ressourcen nacheinander geladen werden, damit jede von ihnen per Pipeline weitergeleitet werden kann. JavaScript kann benutzerdefinierte Anwendungslogik sowie Tracking-Beacons für Analyse und Marketing enthalten, und ihre Verzögerung kann zu einer Verringerung der vom Unternehmen verfolgten Indikatoren führen.
- Bilder können parallel hochgeladen werden. Die ersten paar Bytes der Bilddatei enthalten ihre Größe, die für das Browserlayout erforderlich sein kann, und das parallele Laden progressiver Bilder kann nach der Übertragung von etwa 50% des Gesamtvolumens die visuelle Vollständigkeit gewährleisten.
In Anbetracht der Kompromisse funktioniert diese Strategie in den meisten Fällen gut:
- Benutzerdefinierte Schriftarten werden nacheinander heruntergeladen und teilen die verfügbare Bandbreite mit Bildern im Umfang.
- Sichtbare Bilder werden parallel geladen und teilen sich den Teil der ihnen zugewiesenen Bandbreite.
- Wenn keine Schriftarten oder sichtbaren Bilder mehr vorhanden sind:
- Nicht blockierende Skripte werden nacheinander geladen und teilen die verfügbare Bandbreite mit unsichtbaren Bildern (die außerhalb des Gültigkeitsbereichs liegen).
- Unsichtbare Bilder werden parallel geladen und teilen sich den Teil der ihnen zugewiesenen Bandbreite.
So wird der für den Benutzer sichtbare Inhalt so schnell wie möglich geladen, die Anwendungslogik auf ein Minimum verzögert und unsichtbare Bilder so geladen, dass das Layout so schnell wie möglich fertiggestellt wird.
Beispiel
Verwenden Sie zur Veranschaulichung eine vereinfachte Produktkategorieseite einer typischen E-Commerce-Website:
- Blau - HTML-Datei der Seite selbst.
- Grün - Ein externes Stylesheet (CSS-Datei).
- Orange - Vier externe Skripte (JavaScript). Zwei blockierende Skripte oben auf der Seite und zwei asynchrone. Blockierende Skripte werden in einem dunkleren Orangeton angezeigt.
- Rot ist eine benutzerdefinierte Webschrift.
- Violett - 13 Bilder. Das Seitenlogo und vier Produktbilder werden im Anzeigefenster angezeigt. Weitere 8 Produktbilder müssen gescrollt werden. Die fünf sichtbaren Bilder werden durch einen dunkleren Purpur angezeigt.
Nehmen wir zur Vereinfachung an, dass alle Ressourcen dieselbe Größe und jede Last in 1 Sekunde haben. Das Herunterladen aller Ressourcen dauert insgesamt 20 Sekunden, aber die Reihenfolge und Methode des Ladens sind äußerst wichtig.

So sieht das optimale Laden von Ressourcen in einem Browser aus:

- Die Seite ist in den ersten 4 Sekunden beim Laden von HTML, CSS und Blockieren von Skripten leer: Alle verwenden eine 100% ige Verbindung.
- Bei der 4-Sekunden-Marke werden der Hintergrund und die Seitenstruktur ohne Text oder Bilder angezeigt.
- Nach einer Sekunde, nach ungefähr 5 Sekunden, wird der Seitentext angezeigt.
- Im Intervall von 5-10 Sekunden werden Bilder heruntergeladen, zunächst verschwommen, aber sehr schnell werden sie klar. Nach etwa 7 Sekunden ist das Ergebnis von der endgültigen Version kaum zu unterscheiden.
- Nach ca. 10 Sekunden ist das Laden aller visuellen Inhalte im sichtbaren Teil der Seite abgeschlossen.
- In den nächsten zwei Sekunden wird asynchrones JavaScript geladen und ausgeführt, wobei unkritische Logik (Analysen, Marketing-Tags usw.) ausgeführt wird.
- Während der letzten 8 Sekunden werden die verbleibenden Bilder geladen, falls der Benutzer die Seite scrollt.
Aktuelle Browser-Priorisierung
Alle aktuellen Browser-Engines implementieren
verschiedene Priorisierungsstrategien , von denen keine optimal ist.
Microsoft Edge und Internet Explorer unterstützen keine Priorisierung , daher arbeiten sie mit den Standardeinstellungen für HTTP / 2, bei denen alles parallel geladen wird und die Bandbreite gleichmäßig auf alle Ressourcen verteilt wird. Microsoft Edge wird in zukünftigen Versionen auf die Verwendung der Chromium-Engine umstellen, was die Situation verbessern kann. In unserem Beispiel bleibt der Browser jedoch die meiste Zeit im Seitenkopf hängen, da Bilder die Übertragung blockierender Skripte und Stylesheets verlangsamen.

Optisch führt dies zu einer ziemlich schmerzhaften Erfahrung: Der Benutzer schaut 19 Sekunden lang auf einen leeren Bildschirm, und dann gibt es eine Verzögerung von 1 Sekunde, um den Text anzuzeigen. Seien Sie geduldig, wenn Sie die folgende Animation anzeigen, denn 19 Sekunden lang scheint auf einem leeren Bildschirm nichts zu passieren (obwohl dies der Fall ist):
Safari lädt alle Ressourcen parallel und teilt laut Safari die Bandbreite entsprechend ihrer Wichtigkeit (das Blockieren von Ressourcen wie Skripten und Stylesheets ist wichtiger als Bilder). Bilder werden parallel geladen, aber auch gleichzeitig mit blockierenden Inhalten.

Obwohl Safari Edge in dem Sinne ähnlich ist, dass alles gleichzeitig geladen wird, können Sie durch das Zuweisen von mehr Bandbreite zum Blockieren von Ressourcen Inhalte viel früher anzeigen:

- Nach ca. 8 Sekunden ist das Laden des Stylesheets und der Skripte abgeschlossen, sodass Sie mit dem Rendern der Seite beginnen können. Da die Bilder parallel geladen wurden, können sie auch teilweise angezeigt werden (verschwommen für progressive Bilder). Dies ist immer noch doppelt so langsam wie das optimale Szenario, aber viel besser als in Edge.
- Nach ca. 11 Sekunden wird die Schriftart geladen. Sie können den Text anzeigen. Zu diesem Zeitpunkt werden mehr Daten für die Bilder geladen und sie werden etwas schärfer. Dies ist vergleichbar mit der Situation um die 7-Sekunden-Marke für ein optimales Ladeszenario.
- In den verbleibenden 9 Sekunden werden die Bilder schärfer, wenn mehr Daten heruntergeladen werden, bis der Vorgang in 20 Sekunden abgeschlossen ist.
Firefox erstellt einen Abhängigkeitsbaum, der Ressourcen gruppiert, und plant dann, dass die Gruppen entweder nacheinander geladen werden oder die Bandbreite zwischen Gruppen gemeinsam nutzen. Innerhalb dieser Gruppe teilen sich Ressourcen Bandbreite und laden gleichzeitig. Es ist geplant, Bilder nach Stylesheets zu laden, die das Rendern blockieren und parallel laden. Skripte und Stylesheets, die das Rendern blockieren, werden jedoch auch parallel geladen und profitieren nicht vom Pipelining.

In unserem Beispiel geschieht dies etwas schneller als in Safari, da die Bilder darauf warten, dass das Stylesheet geladen wird:

- Nach ca. 6 Sekunden wird der ursprüngliche Seiteninhalt mit einem Hintergrund und verschwommenen Versionen der Produktbilder angezeigt (im Vergleich zu 8 Sekunden für Safari und 4 Sekunden im besten Fall).
- Nach 8 Sekunden wird die Schriftart geladen, und Sie können den Text zusammen mit etwas schärferen Bildern des Produkts anzeigen (im Vergleich zu Safari im besten Fall 11 Sekunden und 7 Sekunden).
- Während der verbleibenden 12 Sekunden werden die Bilder schärfer, wenn der verbleibende Inhalt geladen wird.
Chrome (und alle Chromium-basierten Browser) priorisieren das Inventar. Dies funktioniert sehr gut, um Ressourcen zu blockieren, die optimal in der richtigen Reihenfolge geladen werden, aber nicht so gut für Bilder. Jedes Bild wird zu 100% geladen, bevor das nächste gestartet wird.

In der Praxis ist dies ein nahezu optimales Download-Szenario. Der einzige Unterschied besteht darin, dass Bilder einzeln und nicht parallel heruntergeladen werden:

- Bis zu 5 Sekunden ist das Laden von Chrome identisch mit dem optimalen Szenario. Der Hintergrund wird in der 4. Sekunde und der Textinhalt in der 5. Sekunde angezeigt.
- In den nächsten 5 Sekunden werden die Bilder des Sichtbarkeitsbereichs einzeln geladen, bis der Vorgang nach etwa 10 Sekunden abgeschlossen ist (im Vergleich zum optimalen Szenario, wenn sie nach etwa 7 Sekunden in einer leicht verschwommenen Form angezeigt werden und für die verbleibenden drei Sekunden schärfer werden).
- Nachdem der visuelle Teil der Seite in 10 Sekunden abgeschlossen ist (identisch mit dem optimalen Szenario), werden die verbleibenden 10 Sekunden für das Ausführen asynchroner Skripts und das Laden versteckter Bilder (sowie im optimalen Szenario) aufgewendet.
Visueller Vergleich
Der visuelle Unterschied ist sehr unterschiedlich, obwohl das technische Laden des gesamten Inhalts dieselbe Zeit in Anspruch nimmt:

Serverseitige Priorisierung
Die HTTP / 2-Priorisierung wird vom Client (Browser) angefordert, und der Server muss basierend auf der Anforderung entscheiden, was zu tun ist.
Eine große Anzahl von Servern unterstützt diese Funktion überhaupt nicht , und der Rest erfüllt eine Clientanforderung. Eine andere Möglichkeit besteht darin, basierend auf der Clientanforderung die beste serverseitige Priorisierung festzulegen.
Gemäß der
Spezifikation ist die HTTP / 2-Priorisierung ein Abhängigkeitsbaum, der die vollständige Kenntnis aller aktuellen Anforderungen erfordert, um Ressourcen relativ zueinander priorisieren zu können. Auf diese Weise können Sie unglaublich komplexe Strategien implementieren, es ist jedoch schwierig, sie auf Browser- oder Serverseite gut zu implementieren (wie verschiedene Browserstrategien und unterschiedliche Ebenen der Serverunterstützung belegen). Um die Verwaltung der Priorisierung zu vereinfachen, haben wir ein einfacheres Schema entwickelt, das dennoch über die für eine optimale Planung erforderliche Flexibilität verfügt.
Das Priorisierungsschema von Cloudflare besteht aus 64 Prioritätsstufen. Innerhalb jeder Stufe gibt es Gruppen von Ressourcen, die bestimmen, wie die Verbindung untereinander aufgeteilt werden soll:

Zuerst werden alle Ressourcen mit einer höheren Priorität heruntergeladen, dann erfolgt ein Übergang zu einer niedrigeren Ebene.
Innerhalb einer bestimmten Prioritätsstufe gibt es drei verschiedene Parallelitätsgruppen:
- 0 : Alle Ressourcen in Gruppe "0" werden nacheinander in der Reihenfolge gesendet, in der sie mit 100% Bandbreite angefordert wurden. Erst nach dem Laden aller Ressourcen der Gruppe "0" werden andere Gruppen auf derselben Ebene berücksichtigt.
- 1 : Alle Ressourcen in der Parallelitätsgruppe "1" werden nacheinander in der Reihenfolge gesendet, in der sie angefordert wurden. Die verfügbare Bandbreite ist gleichmäßig zwischen der Parallelitätsgruppe "1" und der Parallelitätsgruppe "n" verteilt.
- n : Ressourcen in der Parallelitätsgruppe "n" werden parallel übertragen und teilen sich die verfügbare Bandbreite.
In der Praxis ist die Parallelitätsgruppe „0“ nützlich für kritische Inhalte, die nacheinander verarbeitet werden müssen (Skripte, CSS usw.). Die Gruppe „1“ ist nützlich für weniger wichtige Inhalte, die Bandbreite mit anderen Ressourcen teilen können, bei denen die Ressourcen selbst jedoch weiterhin von einer sequentiellen Verarbeitung profitieren (asynchrone Skripte, nicht progressive Bilder usw.). Die Parallelitätsgruppe "n" ist nützlich für Ressourcen, die von der Parallelverarbeitung profitieren (progressive Bilder, Video, Audio usw.).
Standardpriorisierung von Cloudflare
Mit der Option der erweiterten Priorisierung wird die oben beschriebene „optimale“ Reihenfolge des Ressourcenladens implementiert. Die spezifischen Prioritäten lauten wie folgt:

Mit diesem Schema können Sie nacheinander Ressourcen senden, die das Rendern blockieren, dann sichtbare Bilder parallel senden und dann den Rest des Seiteninhalts mit einer gewissen Bandbreitenteilung teilen, um das Laden der Anwendung und des Inhalts auszugleichen. Die
Einschränkung * Wenn erkennbar ist, dass nicht alle Browser zwischen verschiedenen Arten von Stylesheets und Skripten unterscheiden, dies jedoch in allen Fällen viel schneller ist. Eine Beschleunigung von 50%, insbesondere für Edge- und Safari-Besucher, ist nichts Ungewöhnliches:

Festlegen der Priorisierung mit Arbeitnehmern
Eine schnellere Standardarbeit ist großartig, wird jedoch dank der Möglichkeit, die Priorisierung mit Cloudflare Workers-Unterstützung zu konfigurieren, sehr interessant, sodass Websites die Standardpriorität für Ressourcen überschreiben oder ihre eigenen Priorisierungsschemata implementieren können.
Wenn der Worker der Antwort den Header
cf-priority
hinzufügt, wenden die Cloudflare-Edgeserver die angegebene Priorität und Parallelität an. Das Header-Format lautet <Priorität> / <Währung>, daher der
response.headers.set('cf-priority', “30/0”);
setzt für diese Antwort die Priorität 30 und die Parallelität 0. In ähnlicher Weise setzt "30/1" die Parallelität auf "1" und "30 / n" die Parallelität auf n.
Mit dieser Flexibilität kann ein Standort eine beliebige Priorität der Ressourcen für seine Anforderungen festlegen. Um beispielsweise die Priorität einiger wichtiger asynchroner Skripte oder Hauptbilder zu erhöhen: Sie werden heruntergeladen, noch bevor der Browser feststellt, dass sie sich in Reichweite befinden.
Um über Priorisierungsentscheidungen zu informieren, gibt die Laufzeit der Worker auch die vom Browser bei der Priorisierung angeforderten Informationen im Anforderungsobjekt an, die an den Empfänger der Worker-Ereignisse übergeben werden (request.cf.requestPriority). Eingehende Prioritäten sind eine Liste von Attributen, die durch ein Semikolon getrennt sind. Es sieht ungefähr so aus:
weight=192;exclusive=0;group=3;group-weight=127
.
- Gewicht : Gewicht zur Priorisierung von HTTP / 2.
- exklusiv : das exklusive HTTP / 2-Flag (1 für Chromium-basierte Browser, 0 für andere).
- Gruppe : HTTP / 2-Stream-ID für die Anforderungsgruppe (ungleich Null für Firefox).
- Gruppengewicht : HTTP / 2-Gewicht für die Gruppe von Anforderungen (ungleich Null für Firefox).
Dies ist nur der Anfang.
Die Fähigkeit, die Priorität von Antworten zu konfigurieren und zu steuern, ist der Hauptbaustein für eine großartige zukünftige Arbeit. Darüber hinaus beabsichtigen wir, unsere eigenen erweiterten Optimierungen einzuführen. Mit Unterstützung der Mitarbeiter können jedoch alle Standorte und Forscher mit verschiedenen Priorisierungsstrategien experimentieren. Über den Apps Marketplace können Unternehmen auch neue Optimierungsservices über der Arbeitsplattform erstellen und diese für andere Websites verfügbar machen.
Wenn Sie einen Pro-Plan oder höher haben, wechseln Sie im Cloudflare-Dashboard zur Registerkarte "Geschwindigkeit" und aktivieren Sie die "erweiterte HTTP / 2-Priorisierung", um Ihre Site zu beschleunigen.
