Skript-Tag - asynchron und verzögert

547

Ich habe ein paar Fragen zu den Attributen asyncund deferzum <script>Tag, die meines Wissens nur in HTML5-Browsern funktionieren.

Eine meiner Websites enthält zwei externe JavaScript-Dateien, die sich derzeit direkt über dem </body>Tag befinden. das erste ist von Google bezogen und das zweite ist ein lokales externes Skript.

In Bezug auf die Ladegeschwindigkeit der Baustelle

  1. Gibt es einen Vorteil beim Hinzufügen asynczu den beiden Skripten, die ich am Ende der Seite habe?

  2. Wäre es von Vorteil, die asyncOption zu den beiden Skripten hinzuzufügen und sie oben auf der Seite im zu platzieren <head>?

  3. Würde dies bedeuten, dass sie beim Laden der Seite heruntergeladen werden?
  4. Ich gehe davon aus, dass dies zu Verzögerungen bei HTML4-Browsern führen würde, aber würde dies das Laden von Seiten für HTML5-Browser beschleunigen?

Verwenden von <script defer src=...

  1. Würde das Laden der beiden darin enthaltenen Skripte <head>mit dem Attribut deferdie gleichen Auswirkungen haben wie die vorherigen Skripte </body>?
  2. Ich gehe wieder einmal davon aus, dass dies HTML4-Browser verlangsamen würde.

Verwenden von <script async src=...

Wenn ich zwei Skripte mit asyncaktiviert habe

  1. Würden sie gleichzeitig herunterladen?
  2. Oder einzeln mit dem Rest der Seite?
  3. Wird die Reihenfolge der Skripte dann zum Problem? Zum Beispiel hängt ein Skript vom anderen ab. Wenn eines schneller heruntergeladen wird, wird das zweite möglicherweise nicht richtig ausgeführt usw.

Schließlich lasse ich die Dinge so, wie sie sind, bis HTML5 häufiger verwendet wird?

Adam
quelle
5
asyncist neu (ish), gehört aber deferseit IE4 zum IE. deferwurde in jüngerer Zeit zu anderen Browsern hinzugefügt, aber ältere Versionen dieser Browser hängen viel weniger herum.
Alohci
3
Jetzt ist HTML5 sehr beliebt geworden!
September 08
2
deferist dasselbe wie das Platzieren von Skripten am unteren Rand des HTML-Codes, was seit vielen Jahren üblich ist.
vsync
1
@vsync nicht unbedingt wahr, der Browser lädt den JS mit dem Defer-Tag herunter, wenn er das Skript-Tag analysiert, verschiebt jedoch die Ausführung bis kurz vor DOMContentLoaded. Das Herunterladen ist nicht blockierend. Wenn Sie am Ende des HTML-Codes platzieren, wird das Herunterladen und Ausführen des JS verzögert, bis das DOM erstellt ist. Wenn Sie jedoch auf den Download warten, entsteht eine zusätzliche Verzögerung.
Brad Frost
@BradFrost - Das Herunterladen blockiert meiner Ansicht nach in dem Sinne, dass es Internetbandbreite beansprucht, und für diejenigen mit langsamer Verbindung ist es unbedingt erforderlich, zuerst das Dokument zu laden und erst dann, wenn es gerendert wurde, mit dem Herunterladen von Javascript-Dateien zu beginnen . Dies gilt in Fällen, in denen der Inhalt nicht eng an Javascript gekoppelt ist, um alles zu rendern (wie SPA )
vsync

Antworten:

405

Behalten Sie Ihre Skripte direkt vor </body>. Async kann unter bestimmten Umständen mit Skripten verwendet werden, die sich dort befinden (siehe Diskussion unten). Das Aufschieben macht für die dort befindlichen Skripte keinen großen Unterschied, da die DOM-Analyse ohnehin schon so gut wie erledigt ist.

Hier ist ein Artikel, der den Unterschied zwischen asynchron und verzögert erklärt: http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/ .

Ihr HTML wird in älteren Browsern schneller angezeigt, wenn Sie die Skripte direkt am Ende des Textes behalten </body>. Um die Ladegeschwindigkeit in älteren Browsern beizubehalten, möchten Sie sie nirgendwo anders platzieren.

Wenn Ihr zweites Skript vom ersten Skript abhängt (z. B. wenn Ihr zweites Skript die im ersten Skript geladene jQuery verwendet), können Sie sie nicht ohne zusätzlichen Code asynchronisieren, um die Ausführungsreihenfolge zu steuern. Sie können sie jedoch verschieben, da Skripte verschoben werden noch in der richtigen Reihenfolge ausgeführt werden, nur erst nachdem das Dokument analysiert wurde. Wenn Sie diesen Code haben und die Skripte nicht sofort ausgeführt werden müssen, können Sie sie asynchronisieren oder verschieben.

Sie können die Skripte in das <head>Tag einfügen und auf setzen. deferDas Laden der Skripte wird verzögert, bis das DOM analysiert wurde. Dies wird in neuen Browsern, die das Verschieben unterstützen, schnell angezeigt, aber es hilft Ihnen überhaupt nicht in älteren Browsern und es ist nicht wirklich schneller als nur die Skripte direkt davor zu platzieren, </body>was in allen Browsern funktioniert. Sie können also sehen, warum es am besten ist, sie vorher richtig zu stellen </body>.

Async ist nützlicher, wenn es Ihnen wirklich egal ist, wann das Skript geladen wird und nichts anderes, was vom Benutzer abhängig ist, vom Laden des Skripts abhängt. Das am häufigsten genannte Beispiel für die Verwendung von Async ist ein Analyseskript wie Google Analytics, auf das Sie nicht warten möchten. Es muss nicht bald ausgeführt werden, und es steht für sich allein, sodass nichts anderes davon abhängt.

Normalerweise ist die jQuery-Bibliothek kein guter Kandidat für Async, da andere Skripte davon abhängen und Sie Ereignishandler installieren möchten, damit Ihre Seite auf Benutzerereignisse reagieren kann und Sie möglicherweise einen jQuery-basierten Initialisierungscode ausführen müssen, um den Anfangszustand herzustellen der Seite. Es kann asynchron verwendet werden, aber andere Skripte müssen codiert werden, damit sie erst ausgeführt werden, wenn jQuery geladen ist.

jfriend00
quelle
8
Defer sollte sie weiterhin in der richtigen Reihenfolge ausführen, aber vor dem Laden von Dom-Inhalten ausführen. Bedeutet das nicht, dass es schneller ist, es in den Kopf zu stecken, da es mit dem Herunterladen beginnen kann, BEVOR das Body-HTML analysiert wird?
Kevin
9
Sie sagten, das Einfügen headund Einstellen von Skripten defersei nicht schneller als das Einfügen zuvor </body>, aber nach dem, was ich gelesen habe, ist das falsch. Denken Sie darüber nach - wenn Sie die Skripte einfügen <head>, werden sie sofort heruntergeladen, wohingegen </body>alle anderen Elemente zuerst heruntergeladen werden, wenn sie vorher richtig sind .
Nate
12
@Nate - Dadurch wird Ihr Dokument nicht schneller geladen, was mein Punkt ist. Sie haben Recht, dass dies das Laden des Skripts früher verbessern könnte, aber auch das Laden des Dokuments und seines Inhalts verlangsamen könnte, da Sie einen Teil Ihrer Bandbreite und eine der begrenzten Verbindungen verwenden, die der Browser zu einem bestimmten Server herstellen wird Laden Sie das Skript, während es gleichzeitig versucht, Ihren Inhalt zu laden.
jfriend00
4
"Wenn Ihr zweites Skript vom ersten Skript abhängt ... dann können Sie sie weder asynchron noch verzögern" - das ist nicht wahr, wenn sie verzögert ausgeführt werden.
DisgruntledGoat
2
Zu diesem Zeitpunkt ist die </ body> -Anforderung bei Browserentwicklungen seit 2012, als diese Antwort veröffentlicht wurde, nicht wirklich erforderlich.
bgcode
843

Dieses Bild erklärt das normale Skript-Tag, Async und Defer

Geben Sie hier die Bildbeschreibung ein

  • Asynchrone Skripte werden ausgeführt, sobald das Skript geladen wird, sodass die Ausführungsreihenfolge nicht garantiert wird (ein Skript, das Sie am Ende angegeben haben, wird möglicherweise vor der ersten Skriptdatei ausgeführt).

  • Skripts verschieben garantiert die Ausführungsreihenfolge, in der sie auf der Seite angezeigt werden.

Siehe diesen Link: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

Prasanth Bendra
quelle
Ich denke, ein Beispiel mit mehreren Skripten wäre besser gewesen, um ihre Reihenfolge zu veranschaulichen
vsync
4
@writofmandamus Sieht aus wie asyncwird gewinnen. Siehe stackoverflow.com/questions/13821151/…
Monsignore
Danke für die gute Erklärung. Die Bilder sind jedoch nicht maßstabsgetreu. Wenn nur das <script>Tag verwendet wird, ist die Gesamtlänge des Seitenladens um die Zeit länger, die zum Herunterladen der Skriptdatei benötigt wird.
Arni
@BhavikHirani Laut dieser Site wird bei der Verwendung von Async und Defer im selben Skript-Tag Async verwendet, wenn der Browser dies unterstützt, oder es wird auf Defer zurückgegriffen, wenn Async nicht unterstützt wird, Defer jedoch unterstützt wird. Die Verhaltensweisen sind ziemlich unterschiedlich, daher würde ich nicht empfehlen, beide zu verwenden, da das Ergebnis unvorhersehbar ist und eine großartige Quelle für Fehler sein kann.
Adrian Wiik
@arni Nur wenn die Bandbreite voll ausgelastet ist, was selten der Fall ist. Und beide Downloads teilen sich die Bandbreite und blockieren nicht eine. - Weiter: Diese Bilder zeigen das Parsen in Grün, nicht das Herunterladen.
Robert Siemer
213

HTML5 : async,defer

In HTML5 können Sie dem Browser mitteilen, wann Ihr JavaScript-Code ausgeführt werden soll. Es gibt 3 Möglichkeiten:

<script       src="myscript.js"></script>

<script async src="myscript.js"></script>

<script defer src="myscript.js"></script>
  1. Ohne asyncoder deferführt der Browser Ihr Skript sofort aus, bevor die Elemente unter Ihrem Skript-Tag gerendert werden.

  2. Mit async(asynchron) lädt der Browser die HTML-Seite weiter und rendert sie, während der Browser das Skript gleichzeitig lädt und ausführt.

  3. Mit deferführt der Browser Ihr Skript aus, wenn die Analyse der Seite abgeschlossen ist. (Nicht erforderlich, um das Herunterladen aller Bilddateien abzuschließen. Dies ist gut.)

Dinesh
quelle
Die Vorlage blogger.com ist erforderlich, async=""bevor Vorlagenänderungen überprüft und gespeichert werden.
Noobninja
1
Hinweis: Es gibt keine Garantie dafür, dass Skripts in der Reihenfolge ausgeführt werden, in der sie mit Async angegeben wurden. "Wenn Ihr zweites Skript vom ersten Skript abhängt, vermeiden Sie Async."
Faisal Naseer
2
async- Skripte werden in dem Moment ausgeführt, in dem sie heruntergeladen wurden, ohne Berücksichtigung ihrer Reihenfolge in der HTML-Datei.
vsync
30

Beide asyncund deferSkripte werden sofort heruntergeladen, ohne den Parser anzuhalten, und beide unterstützen einen optionalen onloadHandler, um die allgemeine Notwendigkeit zu erfüllen, eine vom Skript abhängige Initialisierung durchzuführen.

Der Unterschied zwischen asyncund deferdreht sich um die Ausführung des Skripts. Jedes asyncSkript wird bei der ersten Gelegenheit ausgeführt, nachdem der Download abgeschlossen ist und bevor das Fenster geladen wird. Dies bedeutet, dass asyncSkripte möglicherweise (und wahrscheinlich) nicht in der Reihenfolge ausgeführt werden, in der sie auf der Seite vorkommen. Während die deferSkripte andererseits garantiert in der Reihenfolge ausgeführt werden, in der sie auf der Seite vorkommen. Diese Ausführung beginnt, nachdem die Analyse vollständig abgeschlossen ist, jedoch vor dem DOMContentLoadedEreignis des Dokuments .

Quelle & weitere Details: hier .

Zameer Khan
quelle
25

Konnte mit der gleichen Art von Problem konfrontiert und jetzt klar verstanden, wie beide funktionieren werden. Hoffentlich ist dieser Referenzlink hilfreich ...

Async

Wenn Sie das asynchrone Attribut zu Ihrem Skript-Tag hinzufügen, geschieht Folgendes.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. Stellen Sie parallele Anforderungen zum Abrufen der Dateien.
  2. Analysieren Sie das Dokument weiter, als wäre es nie unterbrochen worden.
  3. Führen Sie die einzelnen Skripte aus, sobald die Dateien heruntergeladen wurden.

Verschieben

Defer ist Async mit einem großen Unterschied sehr ähnlich. Folgendes passiert, wenn ein Browser auf ein Skript mit dem Attribut defer stößt.

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. Stellen Sie parallele Anforderungen, um die einzelnen Dateien abzurufen.
  2. Analysieren Sie das Dokument weiter, als wäre es nie unterbrochen worden.
  3. Beenden Sie das Parsen des Dokuments, auch wenn die Skriptdateien heruntergeladen wurden.
  4. Führen Sie jedes Skript in der Reihenfolge aus, in der es im Dokument gefunden wurde.

Referenz: Unterschied zwischen Async und Defer

Kamesh
quelle
7

asyncund deferlädt die Datei während der HTML-Analyse herunter. Beide unterbrechen den Parser nicht.

  • Das Skript mit asyncAttribut wird ausgeführt, sobald es heruntergeladen wurde. Während das Skript mit deferAttribut nach Abschluss der DOM-Analyse ausgeführt wird.

  • Die mit geladenen Skripte asyncgarantieren keine Bestellung. Während die mit deferAttributen geladenen Skripte die Reihenfolge beibehalten, in der sie im DOM angezeigt werden.

Verwenden Sie diese Option, <script async>wenn das Skript auf nichts angewiesen ist. Wann hängt das Skript von der Verwendung ab?

Die beste Lösung wäre das Hinzufügen am unteren Rand des Körpers. Es wird kein Problem mit dem Blockieren oder Rendern geben.

NavyaKumar
quelle
Ich möchte hier nur etwas klarstellen, hier passieren zwei Dinge: 1. Herunterladen der Ressource 2. Ausführung der Ressource. Das Herunterladen von Ressourcen in beiden Fällen (Async und Defer) blockiert nicht, dh sie blockieren nicht das Parsen von HTML, während das Ausführen in Async das Parsen blockiert und im Falle von Defer die Ausführung erfolgt, nachdem das HTML-Markup analysiert wurde. daher in diesem Fall nicht blockierend.
pOoOf
5

Ich denke, Jake Archibald hat uns 2013 einige Einblicke gegeben, die dem Thema noch mehr Positivität verleihen könnten:

https://www.html5rocks.com/de/tutorials/speed/script-loading/

Der Heilige Gral lässt eine Reihe von Skripten sofort herunterladen, ohne das Rendern zu blockieren, und wird so schnell wie möglich in der Reihenfolge ausgeführt, in der sie hinzugefügt wurden. Leider hasst HTML Sie und lässt Sie das nicht zu.

(...)

Die Antwort befindet sich tatsächlich in der HTML5-Spezifikation, obwohl sie unten im Abschnitt zum Laden von Skripten versteckt ist. " Das asynchrone IDL-Attribut steuert, ob das Element asynchron ausgeführt wird oder nicht. Wenn das Flag" Force-Async "des Elements gesetzt ist, muss das asynchrone IDL-Attribut beim Abrufen true zurückgeben und beim Setzen das" force-async ". Flag muss zuerst deaktiviert werden ... ".

(...)

Skripte, die dynamisch erstellt und dem Dokument hinzugefügt werden, sind standardmäßig asynchron . Sie blockieren das Rendern nicht und werden nicht ausgeführt, sobald sie heruntergeladen werden. Dies bedeutet, dass sie möglicherweise in der falschen Reihenfolge ausgegeben werden. Wir können sie jedoch explizit als nicht asynchron markieren:

[
    '//other-domain.com/1.js',
    '2.js'
].forEach(function(src) {
    var script = document.createElement('script');
    script.src = src;
    script.async = false;
    document.head.appendChild(script);
});

Dies gibt unseren Skripten eine Mischung aus Verhalten, die mit einfachem HTML nicht erreicht werden kann. Da Skripts explizit nicht asynchron sind, werden sie einer Ausführungswarteschlange hinzugefügt, der gleichen Warteschlange, zu der sie in unserem ersten HTML-Beispiel hinzugefügt wurden. Durch die dynamische Erstellung werden sie jedoch außerhalb der Dokumentanalyse ausgeführt, sodass das Rendern beim Herunterladen nicht blockiert wird (verwechseln Sie das Laden von nicht asynchronen Skripten nicht mit dem Synchronisieren von XHR, was niemals gut ist).

Das obige Skript sollte inline im Kopf der Seiten enthalten sein, Skript-Downloads so schnell wie möglich in die Warteschlange stellen, ohne das progressive Rendern zu stören, und so schnell wie möglich in der von Ihnen angegebenen Reihenfolge ausgeführt werden. "2.js" kann kostenlos vor "1.js" heruntergeladen werden, wird jedoch erst ausgeführt, wenn "1.js" entweder erfolgreich heruntergeladen und ausgeführt wurde oder dies nicht tut. Hurra! Async-Download aber geordnete Ausführung !

Dies ist jedoch möglicherweise nicht der schnellste Weg, um Skripte zu laden:

(...) Im obigen Beispiel muss der Browser das Skript analysieren und ausführen, um herauszufinden, welche Skripte heruntergeladen werden sollen. Dies verbirgt Ihre Skripte vor Preload-Scannern. Browser verwenden diese Scanner, um Ressourcen auf Seiten zu ermitteln, die Sie wahrscheinlich als Nächstes besuchen, oder um Seitenressourcen zu ermitteln, während der Parser von einer anderen Ressource blockiert wird.

Wir können die Auffindbarkeit wieder hinzufügen, indem wir dies in den Kopf des Dokuments setzen:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

Dies teilt dem Browser mit, dass die Seite 1.js und 2.js benötigt. link [rel = subresource] ähnelt link [rel = prefetch], weist jedoch eine andere Semantik auf. Leider wird es derzeit nur in Chrome unterstützt, und Sie müssen deklarieren, welche Skripte zweimal geladen werden sollen, einmal über Linkelemente und erneut in Ihrem Skript.

Korrektur: Ich habe ursprünglich angegeben, dass diese vom Preload-Scanner erfasst wurden, nicht vom regulären Parser. Der Preload-Scanner könnte diese jedoch noch aufnehmen, während Skripte, die im ausführbaren Code enthalten sind, niemals vorinstalliert werden können. Vielen Dank an Yoav Weiss, der mich in den Kommentaren korrigiert hat.

mjfneto
quelle
1

Es scheint, dass das Verhalten von Defer und Async zumindest von der Ausführungsphase browserabhängig ist. HINWEIS: Aufschieben gilt nur für externe Skripte. Ich gehe davon aus, dass Async dem gleichen Muster folgt.

In IE 11 und darunter scheint die Reihenfolge wie folgt zu sein:

  • asynchron (könnte teilweise beim Laden der Seite ausgeführt werden)
  • keine (konnte beim Laden der Seite ausgeführt werden)
  • Aufschieben (wird ausgeführt, nachdem die Seite geladen wurde, alle aufgeschoben in der Reihenfolge der Platzierung in der Datei)

In Edge, Webkit usw. scheint das asynchrone Attribut entweder ignoriert oder am Ende platziert zu werden:

  • data-pagespeed-no-defer (wird vor allen anderen Skripten ausgeführt, während die Seite geladen wird)
  • keine (könnte ausgeführt werden, während die Seite geladen wird)
  • Aufschieben (wartet bis das DOM geladen ist, alle aufgeschoben in der Reihenfolge der Platzierung in der Datei)
  • asynchron (scheint zu warten, bis DOM geladen ist)

In neueren Browsern wird das Attribut data-pagespeed-no-defer vor allen anderen externen Skripten ausgeführt. Dies gilt für Skripte, die nicht vom DOM abhängen.

HINWEIS: Verwenden Sie defer, wenn Sie eine explizite Reihenfolge für die Ausführung Ihrer externen Skripte benötigen. Dies weist den Browser an, alle zurückgestellten Skripte in der Reihenfolge ihrer Platzierung in der Datei auszuführen.

ASIDE: Die Größe der externen Javascripts spielte beim Laden eine Rolle ... hatte jedoch keinen Einfluss auf die Ausführungsreihenfolge.

Wenn Sie sich Sorgen über die Leistung Ihrer Skripte machen, sollten Sie eine Minimierung in Betracht ziehen oder sie einfach dynamisch mit einer XMLHttpRequest laden.

Charles Owen
quelle
data-pagespeed-no-deferist ein Attribut, das vom serverseitigen PageSpeed-Modul verwendet wird . Das data-pagespeed-no-deferAttribut selbst hat in keinem Browser eine Auswirkung.
Qtax