Preload:Wozu ist es gut?

Vorladen (spec) ist ein neuer Webstandard, der darauf abzielt, die Leistung zu verbessern und Webentwicklern eine genauere Ladekontrolle zu bieten. Es gibt Entwicklern die Möglichkeit, benutzerdefiniertes Laden zu definieren Logik, ohne die Leistungseinbußen zu erleiden, die skriptbasierte Ressourcenlader erleiden. Vor ein paar Wochen habe ich den Preload-Support in Chrome Canary ausgeliefert, und abgesehen von unerwarteten Fehlern wird Chrome Mitte April stabil sein. Aber was ist das für eine Vorspannung? Was tut es? Und wie kann es Ihnen helfen?

Vorladen (spec) ist ein neuer Webstandard, der darauf abzielt, die Leistung zu verbessern und Webentwicklern eine genauere Ladekontrolle zu bieten. Es gibt Entwicklern die Möglichkeit, benutzerdefiniertes Laden zu definieren Logik, ohne die Leistungseinbußen zu erleiden, die skriptbasierte Ressourcenlader erleiden.

Weiterführende Literatur zu Smashing:

  • Wahrgenommene Leistung
  • Vorbereitung auf HTTP/2
  • Alles, was Sie über AMP wissen müssen
  • Progressive Verbesserung
  • Verbesserung der Leistung des Smashing Magazine

Vor ein paar Wochen habe ich die Preload-Unterstützung in Chrome Canary ausgeliefert, und abgesehen von unerwarteten Fehlern wird Chrome Mitte April stabil sein. Aber was ist das für eine Vorspannung? Was tut es? Und wie kann es Ihnen helfen?

Nun, <link rel=“preload”> ist eine deklarative Abrufdirektive.

Aus menschlicher Sicht ist es eine Möglichkeit, einem Browser zu sagen, dass er mit dem Abrufen einer bestimmten Ressource beginnen soll, da wir als Autoren (oder als Serveradministratoren oder als Entwickler von Smart-Servern) wissen, dass der Browser diese bestimmte Ressource ziemlich bald benötigen wird.

Hatten wir das nicht schon?

Irgendwie, aber nicht wirklich. <link rel=“prefetch”> wird seit langem im Web unterstützt und hat eine anständige Browserunterstützung. Darüber hinaus haben wir auch <link rel=“subresource”> unterstützt in Chrome für einige Zeit. Was ist also neu am Vorladen? Wie unterscheidet sie sich von diesen anderen Richtlinien? Sie alle sagen dem Browser, dass er Dinge abrufen soll, richtig?

Nun, das tun sie, aber es gibt signifikante Unterschiede zwischen ihnen. Unterschiede, die eine glänzende neue Richtlinie rechtfertigen, die viele Anwendungsfälle angeht, die die alten nie taten.

<link rel=“prefetch”> ist eine Anweisung, die einen Browser anweist, eine Ressource abzurufen, die wahrscheinlich benötigt wird für die nächste Navigation. Das bedeutet meistens, dass die Ressource mit extrem niedriger Priorität abgerufen wird (da alles, was der Browser weiß auf der aktuellen Seite benötigt wird, ist wichtiger als eine Ressource, die wir raten könnte im nächsten benötigt werden). Das bedeutet, dass der Hauptanwendungsfall von Prefetch darin besteht, die nächste Navigation zu beschleunigen und nicht die aktuelle.

<link rel=“subresource”> war ursprünglich geplant, um die aktuelle Navigation in Angriff zu nehmen, scheiterte aber auf spektakuläre Weise daran. Da der Webentwickler keine Möglichkeit hatte, die Priorität der Ressource zu definieren, lud der Browser (eigentlich nur Chrome- und Chromium-basierte Browser) sie mit relativ niedriger Priorität herunter, was bedeutete, dass in den meisten Fällen die Ressourcenanforderung herauskam ungefähr zur gleichen Zeit, als wenn die Subressource überhaupt nicht vorhanden wäre.

Wie kann Preload besser werden?

Preload ist für die aktuelle Navigation bestimmt, genau wie Subressource, aber es enthält einen kleinen, aber signifikanten Unterschied. Es hat einen as Attribut, das es dem Browser ermöglicht, eine Reihe von Dingen zu tun, die Subressource und Prefetch nicht ermöglicht haben:

  • Der Browser kann die richtige Ressourcenpriorität festlegen , sodass es entsprechend geladen wird und keine wichtigeren Ressourcen verzögert oder weniger wichtigen Ressourcen hinterherhängt.
  • Der Browser kann sicherstellen, dass die Anfrage den richtigen Content-Security-Policy-Anweisungen unterliegt und nicht an den Server geht, wenn dies nicht der Fall sein sollte.
  • Der Browser kann den entsprechenden Accept senden Kopfzeilen basierend auf dem Ressourcentyp. (z. B. Werbung für die Unterstützung von „image/webp“ beim Abrufen von Bildern)
  • Der Browser kennt den Ressourcentyp, sodass er später feststellen kann, ob die Ressource für zukünftige Anforderungen wiederverwendet werden könnte, die dieselbe Ressource benötigen.

Preload ist auch anders, da es einen funktionalen onload hat event (was zumindest in Chrome bei den anderen beiden rel nicht funktionierte Werte).

Darüber hinaus blockiert das Vorladen nicht den onload des Fensters Veranstaltung , es sei denn, die Ressource wird auch von einer Ressource angefordert, die dieses Ereignis blockiert.

Die Kombination all dieser Eigenschaften ermöglicht eine Reihe neuer Funktionen, die bisher nicht möglich waren.

Lassen Sie uns sie durchgehen, sollen wir?

Laden von spät entdeckten Ressourcen

Die grundlegende Art und Weise, wie Sie das Vorabladen verwenden können, besteht darin, spät entdeckte Ressourcen frühzeitig zu laden . Während die meisten Markup-basierten Ressourcen ziemlich früh vom Preloader des Browsers entdeckt werden, sind nicht alle Ressourcen Markup-basiert. Einige der Ressourcen sind in CSS und JavaScript versteckt, und der Browser kann nicht wissen, dass er sie brauchen wird, bis es schon ziemlich spät ist. Daher verzögern diese Ressourcen in vielen Fällen das erste Rendern, das Rendern von Text oder das Laden kritischer Teile der Seite.

Jetzt haben Sie die Möglichkeit, dem Browser zu sagen:„Hey, Browser! Hier ist eine Ressource, die Sie später brauchen werden, also fangen Sie jetzt an, sie zu laden.“

Das würde in etwa so aussehen:

<link rel="preload" href="late_discovered_thing.js" as="script">

Die as -Attribut teilt dem Browser mit, was er herunterladen wird. Möglich as Zu den Werten gehören:

  • "script" ,
  • "style" ,
  • "image" ,
  • "media" ,
  • und "document" .

(Die vollständige Liste finden Sie in der Abrufspezifikation.)

Weglassen des as Attribut oder einen ungültigen Wert ist gleichbedeutend mit einer XHR-Anfrage, bei der der Browser nicht weiß, was er abruft, und es mit einer ziemlich niedrigen Priorität abruft.

Frühzeitiges Laden von Schriftarten

Eine beliebte Inkarnation des Musters „spät entdeckte kritische Ressourcen“ sind Webfonts. Einerseits sind sie in den meisten Fällen entscheidend für die Darstellung von Text auf der Seite (es sei denn, Sie verwenden die CSS-Werte für glänzende Schriftarten). Andererseits sind sie tief in CSS vergraben, und selbst wenn der Preloader des Browsers CSS geparst hat, kann nicht sicher sein, dass sie benötigt werden, bis er auch weiß, dass die Selektoren, die sie benötigen, tatsächlich für einige der DOM-Knoten gelten. Theoretisch könnten Browser das herausfinden, aber keiner von ihnen, und wenn sie es täten, könnte es zu falschen Downloads führen, wenn die Schriftregeln später außer Kraft gesetzt werden, sobald weitere CSS-Regeln hinzukommen.

Kurz gesagt, es ist kompliziert.

Aber Sie könnten von all dieser Komplexität wegkommen, indem Sie Vorabladeanweisungen für Schriftarten hinzufügen Sie wissen, dass sie gebraucht werden. Etwas wie:

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

Ein Punkt, den es wert ist, noch einmal erwähnt zu werden:Sie müssen eine crossorigin hinzufügen -Attribut beim Abrufen von Schriftarten, da sie im anonymen Modus CORS abgerufen werden. Ja, auch wenn Ihre Schriftarten denselben Ursprung wie die Seite haben. Entschuldigung.

Auch die type Das Attribut soll sicherstellen, dass diese Ressource nur auf Browsern vorgeladen wird, die diesen Dateityp unterstützen. Derzeit unterstützt nur Chrome das Vorladen und auch WOFF2, aber in Zukunft werden möglicherweise mehr Browser das Vorladen unterstützen, und wir können nicht davon ausgehen, dass sie auch WOFF2 unterstützen. Dasselbe gilt für alle Ressourcentypen, die Sie vorab laden, und deren Browserunterstützung nicht allgegenwärtig ist.

Dynamisches Laden ohne Ausführung

Ein weiteres interessantes Szenario, das plötzlich möglich wird, ist eines, in dem Sie eine Ressource herunterladen möchten, weil Sie wissen, dass Sie sie brauchen werden , aber Sie möchten es noch nicht ausführen. Stellen Sie sich beispielsweise ein Szenario vor, in dem Sie ein Skript an einem bestimmten Punkt im Leben der Seite ausführen möchten, ohne die Kontrolle über das Skript zu haben (also ohne die Möglichkeit, einen runNow() hinzuzufügen Funktion dazu).

Heutzutage sind Sie in den Möglichkeiten, dies zu tun, sehr eingeschränkt. Wenn Sie das Skript nur an der Stelle einfügen, an der es ausgeführt werden soll, muss der Browser das Skript herunterladen, bevor es ausgeführt werden kann, was eine Weile dauern kann. Sie könnten das Skript vorher mit XHR herunterladen, aber der Browser weigert sich, es wiederzuverwenden, da die Ressource nicht mit demselben Typ heruntergeladen wurde wie der, der jetzt versucht, die Ressource zu verwenden.

Was können Sie also tun?

Vor dem Preload nicht viel. (In einigen Fällen können Sie eval() den Inhalt des Skripts, aber das ist nicht immer machbar oder ohne Seiteneffekte.) Aber mit Preload können Sie!


var preload = document.createElement("link");
link.href = "myscript.js";
link.rel = "preload";
link.as = "script";
document.head.appendChild(link);

Sie können dies früher im Seitenladeprozess ausführen, lange vor dem Punkt, an dem das Skript ausgeführt werden soll (aber sobald Sie ziemlich sicher sind, dass das Laden des Skripts andere, wichtigere Ressourcen, die geladen werden müssen, nicht stört). Wenn Sie es dann ausführen möchten, fügen Sie einfach einen script ein Tag und gut ist.


var script = document.createElement("script");
script.src = "myscript.js";
document.body.appendChild(script);

Markup-basierter asynchroner Loader

Ein weiterer cooler Hack ist die Verwendung von onload -Handler, um eine Art Markup-basierten Async-Loader zu erstellen. Scott Jehl war der erste, der damit als Teil seiner loadCSS-Bibliothek experimentierte. Kurz gesagt, Sie können Folgendes tun:

<link rel="preload" as="style" href="async_style.css" onload="this.rel='stylesheet'">

und erhalten Sie asynchron geladene Stile im Markup! Scott hat auch eine nette Demo-Seite für diese Funktion.

Dasselbe kann auch für asynchrone Skripte funktionieren.

Wir haben bereits <script async> du sagst? Nun, <script async> ist großartig, aber es blockiert das Onload-Ereignis des Fensters. In einigen Fällen ist es genau das, was Sie möchten, in anderen Fällen jedoch weniger.

Angenommen, Sie möchten ein Analyseskript herunterladen. Sie möchten, dass es ziemlich schnell heruntergeladen wird (um zu vermeiden, dass Besucher verloren gehen, die das Analyseskript nicht erfasst hat), aber Sie möchten nicht, dass es Metriken verzögert, die sich auf die Benutzererfahrung auswirken, und insbesondere möchten Sie nicht, dass es verzögert wird laden. (Sie können behaupten, dass Onload nicht die einzige Metrik ist, die sich auf Benutzer auswirkt, und Sie hätten Recht, aber es ist immer noch schön, das sich drehende Ladesymbol etwas früher zu stoppen).

Mit Preload ist das ganz einfach:


<link rel="preload" as="script" href="async_script.js"
onload="var script = document.createElement('script');
        script.src = this.href;
        document.body.appendChild(script);">

(Es ist wahrscheinlich keine gute Idee, lange JS-Funktionen als onload einzufügen Attribute, daher möchten Sie diesen Teil vielleicht als Inline-Funktion definieren.)

Responsives Laden

Da Preload ein Link ist , laut Spezifikation hat es einen media Attribut. (Es wird derzeit nicht in Chrome unterstützt, wird es aber bald.) Dieses Attribut kann das bedingte Laden von Ressourcen aktivieren.

Wozu ist das gut? Angenommen, der anfängliche Darstellungsbereich Ihrer Website verfügt über eine große interaktive Karte für die Desktop-Version der Website mit breitem Darstellungsbereich, zeigt jedoch nur eine statische Karte für die mobile Version mit schmalem Darstellungsbereich an.

Wenn Sie klug vorgehen, möchten Sie nur eine dieser Ressourcen laden und nicht beide . Und die einzige Möglichkeit, dies zu tun, wäre, sie dynamisch mit JS zu laden. Aber dadurch machen Sie diese Ressourcen für den Preloader unsichtbar und sie werden möglicherweise später als nötig geladen, was sich auf die visuelle Erfahrung Ihrer Benutzer auswirken und negative Auswirkungen haben kann Ihre SpeedIndex-Punktzahl.

Was können wir tun, um sicherzustellen, dass der Browser diese Ressourcen so früh wie möglich erkennt?

Du hast es erraten! Vorladen.

Wir können Preload verwenden, um sie im Voraus zu laden , und wir können seinen media verwenden Attribut, sodass nur das erforderliche Skript wird vorgeladen:

<link rel="preload" as="image" href="map.png" media="(max-width: 600px)">

<link rel="preload" as="script" href="map.js" media="(min-width: 601px)">

Überschriften

Eine weitere kostenlose Funktion von Link-Tags ist, dass sie als HTTP-Header dargestellt werden können. Das bedeutet, dass Sie für die meisten Markup-Beispiele, die ich oben gezeigt habe, einen HTTP-Antwort-Header haben können, der genau dasselbe tut. (Die einzige Ausnahme ist der onload -bezogenes Beispiel. Sie können einen Onload-Handler nicht als Teil eines HTTP-Headers definieren.)

Beispiele für solche HTTP-Antwort-Header können wie folgt aussehen:

Link: <thing_to_load.js>;rel="preload";as="script"

Link: <thing_to_load.woff2>;rel="preload";as="font";crossorigin

HTTP-Header können sich als nützlich erweisen, wenn die Person, die die Optimierung durchführt, nicht dieselbe Person ist, die für die Bearbeitung des Markups verantwortlich ist. Das prominenteste Beispiel ist eine externe Optimierungsmaschine das den Inhalt scannt und optimiert (vollständige Offenlegung:Ich arbeite an einem).

Andere Beispiele können ein separates Performance-Team sein, das solche Optimierungen hinzufügen möchte, oder ein Optimierungs-Build-Prozess, bei dem das Vermeiden von HTML-Fummelei die Komplexität erheblich reduziert.

Funktionserkennung

Ein letzter Punkt:In einigen unserer obigen Beispiele verlassen wir uns darauf, dass das Vorabladen für grundlegende Funktionen wie das Laden von Skripten oder Stilen unterstützt wird. Was passiert in Browsern, in denen dies nicht zutrifft?

Alles geht kaputt!

Das wollen wir nicht. Als Teil der Preload-Bemühungen haben wir also auch die DOM-Spezifikation geändert, sodass die Erkennung von unterstütztem rel funktioniert Keywords wären möglich.

Ein Beispiel für die Merkmalserkennung Funktion könnte etwa so aussehen:

Dadurch können Sie Fallback-Lademechanismen bereitstellen in Fällen, in denen der Mangel an Preload-Unterstützung Ihre Website beschädigen würde. Praktisch!

Deckt HTTP/2 Push nicht dieselben Anwendungsfälle ab?

Nicht wirklich. Obwohl es einige Überschneidungen zwischen den Funktionen gibt, ergänzen sie sich größtenteils gegenseitig.

HTTP/2 Push hat den Vorteil, dass es Ressourcen pushen kann für die der Browser die Anfrage noch nicht gesendet hat. Das bedeutet, dass Push Ressourcen senden kann, bevor das HTML überhaupt an den Browser gesendet wird. Es kann auch verwendet werden, um Ressourcen über eine offene HTTP/2-Verbindung nach unten zu senden, ohne dass eine Antwort erforderlich ist, an die HTTP-Link-Header angehängt werden können.

Andererseits kann Preload verwendet werden, um Anwendungsfälle zu lösen, die HTTP/2 nicht kann . Wie wir gesehen haben, weiß die Anwendung beim Vorladen, dass die Ressource geladen wird, und kann benachrichtigt werden, sobald die Ressource vollständig geladen wurde. Dafür wurde HTTP/2 Push nicht entwickelt. Darüber hinaus kann HTTP/2 Push nicht für Ressourcen von Drittanbietern verwendet werden, während Preload für sie genauso effizient verwendet werden kann wie für Ressourcen von Erstanbietern.

Außerdem kann HTTP/2 Push den Browser-Cache und den nicht globalen Cookie-Status nicht berücksichtigen . Während der Cache-Status möglicherweise mit der neuen Cache-Digest-Spezifikation aufgelöst wird, kann für nicht globale Cookies nichts getan werden, sodass Push nicht für Ressourcen verwendet werden kann, die auf solche Cookies angewiesen sind. Für solche Ressourcen ist Preload Ihr Freund.

Ein weiterer Vorteil von Preload ist, dass es Inhaltsaushandlungen durchführen kann, während HTTP/2 Push dies nicht kann. Das bedeutet, wenn Sie Client-Hinweise verwenden möchten, um das richtige Bild zum Senden an den Browser herauszufinden, oder Accept: Kopfzeilen, um das beste Format herauszufinden, kann Ihnen HTTP/2 Push nicht helfen.

Also …

Ich hoffe, Sie sind jetzt davon überzeugt, dass das Vorabladen eine Reihe neuer Ladefunktionen eröffnet, die vorher nicht möglich waren, und Sie freuen sich darauf, es zu verwenden.

Was ich von Ihnen verlange, ist, Chrome Canary zu holen, mit dem Preload herumzuspielen, es in Stücke zu brechen und zu mir zurück zu jammern. Es ist eine neue Funktion und wie jede neue Funktion kann sie Fehler enthalten . Bitte helfen Sie mir, sie zu finden und so früh wie möglich zu beheben.