2017-03-22 1 views
6

Nach Zurückstellungs attirbute MDN says:Werden verzögerte Skripts vor dem DOMContentLoaded-Ereignis ausgeführt?

Dieses Boolean Attribute an einen Browser, um anzuzeigen, gesetzt, dass das Skript ausgeführt werden soll, nachdem das Dokument analysiert wurde, aber vor DOMContentLoaded Brennen. Das Defer-Attribut sollte nur für externe Skripts verwendet werden.

Auf DOMContentLoadedMDN also says:

Das DOMContentLoaded Ereignis ausgelöst wird, wenn die anfängliche HTML-Dokument vollständig geladen und analysiert wurde, ohne für Stylesheets warten ...

So DOMContentLoaded wird gefeuert, bevor CSSOM bereit ist. Dies bedeutet, dass zurückgestellte Skripte ausgeführt werden, bevor CSSOM bereit ist. Aber wenn das der Fall ist, dürfen die Scripts nicht in der Lage sein, korrekte css-Eigenschaftswerte zu erhalten und css nicht korrekt anzuwenden. Aber es ist nicht wahr, wir wissen, dass alle zurückgestellten Skripte gut funktionieren.

  1. Ist MDN Dokumentation technisch falsch?
  2. Wo finde ich die offizielle Dokumentation von DOMContentLoaded`? Ich suchte in https://dom.spec.whatwg.org/, konnte es aber nicht finden.

P. S: Bitte nicht, dass google says die CSSOM ist aufbauen, bevor sie eine Inline-javscript

enter image description here

Aber Google ist technisch nicht korrekt ausgeführt wird. Inline-JavaScript wird ausgeführt, bevor CSSOM bereit ist. Und aus meinen Tests habe ich festgestellt, dass MDN korrekt ist und wenn js-Dateien (sowohl verzögert als auch nicht zurückgestellt) vor CSS-Dateien heruntergeladen werden (oder js inline ist), dann wird js ausgeführt, bevor CSSOM bereit ist. Js könnte also Stile falsch behandeln. Um dies zu vermeiden, benötigen wir einen Force-Reflow vor allen js-Logiken.

Also, wenn ein Benutzer unsere Website mit allen js besucht bereits zwischengespeichert und CSS nicht zwischengespeichert ODER js wird heruntergeladen vor css dann (s) er möglicherweise falsch gerenderten Seite sehen. Um dies zu vermeiden, sollten wir in allen js-Dateien unserer Websites Force Reflow hinzufügen.

+0

Auch eine ähnliche Diskussion auf http://stackoverflow.com/q los ist/42891628/3429430 – user31782

Antwort

2

Ich benutze deferated script loading. Es gab eine langwierige technische Erklärung von einem Typen, der ein bekannter Performance Guru ist. Er stellt eindeutig fest, dass Deferred der richtige Weg ist (aus diesem und jenem technischen Grund, unterstützt durch alle Arten von Daten und Diagrammen, den viele Leute als offen für Diskussionen zu empfinden schienen, re: async).

Also fing ich an, damit zu arbeiten. Verzögerte Skripts haben den Vorteil, dass sie asynchron herunterladen, aber in der angegebenen Reihenfolge ausgeführt werden, was ein Problem mit async sein kann (z. B. können Sie Ihr App-Paket vor dem Lieferantenpaket laden, da Sie die Ausführungsreihenfolge der asynchronen Skripts nicht steuern "in dieser Reihenfolge").

Allerdings habe ich sofort herausgefunden, dass, obwohl dies das Problem löst, dies bedeuten könnte, dass das CSS-Paket nicht geladen wird, je nachdem, wie Sie Ihre Bündel greifen. Je nachdem, wie Sie die Dinge einrichten, können Sie mit unausgefallenen Inhalten enden. Beachten Sie, dass sie für den Aufschub sagen, dass Sie nicht in die Dom schreiben sollten usw.in diesen Skripten (was wiederum in Bezug auf Ihre Dokumentation Sinn macht).

So scheint es, dass Ihre Dokumentation korrekt ist. Der Effekt wird leicht reproduziert.

Wie komme ich raus? die einfachste Art und Weise, ist wie folgt:

<script src="css.bundle.js"></script> 
<script src="vendor.bundle.js" defer></script> 
<script src="angular.bundle.js" defer></script> 
<script src="app.bundle.js" defer></script> 

Dies stellt sicher, dass die CSS-Lasten in der ersten, so dass Ihre Homepage und so wird schön auf auftauchen, und stellt auch sicher, dass (obwohl alle drei laden async) , das app.bundle wird zuletzt ausführen, um sicherzustellen, dass alle anderen Abhängigkeiten in Ordnung sind.

Also, Sie nehmen das absolute Minimum an CSS benötigt, um die App zu kicken, erstellen Sie das als ein Bündel, und laden Sie es zuerst, vor allem. Ansonsten können Sie in Ihrem CSS pro Modul/Komponente und so weiter bündeln.

Es gibt viel mehr zu diesem Thema und ich könnte wahrscheinlich mehr tun, aber wieder (ich werde versuchen, die Referenz zu finden), das wurde offenkundig von diesem Performance-Assistenten empfohlen, also habe ich es versucht und es scheint ziemlich effektiv zu sein mich.

Edit: Faszinierend, während auf der Suche nach dieser Referenz (die ich noch nicht gefunden habe), ging ich durch eine Handvoll "Experten" zu diesem Thema. Die Empfehlungen sind sehr unterschiedlich. Einige sagen, Async ist in jeder Hinsicht weit überlegen, manche sagen, dass sie aufschieben. Die Jury scheint sich wirklich mit dem Thema zu befassen, insgesamt würde ich sagen, dass es wahrscheinlich mehr damit zu tun hat, wie Sie Ihre Skripte aufbauen, als ob einer tatsächlich besser ist als der andere.

Nochmals bearbeiten: Hier sind noch ein paar Beweise. Ich habe einen Performance Analyzer auf einer Stub-Website unter Verwendung der obigen einfachen Lade-Sequenz laufen lassen und die Skripte bewusst so naiv gemacht, dass sie in einer Zeitleiste sichtbar sind.

Hier ist eine SS des Ergebnisses: Hier sind vier gelbe Kästchen. Die ersten drei sind die Bewertungen der Skripte. Der vierte (wenn Sie im Tool mit der Maus darüber fahren, dies ist nur die SS-Erinnerung) ist das Ereignis DOMContentLoaded (das mit der roten Ecke).

Scripts loading/evaluating before DOMContentLoaded event

+0

Was macht 'css.bundle.js'? Erzwingt "defer" es, den Browser zum ersten Download von 'css resources' und dann' css.bundle.js' zu zwingen (bis jetzt ist CSSOM bereit) und sind all die zurückgestellten Skripte, die nach 'css.bundle.js' heruntergeladen werden sollen? – user31782

+0

CSS-Bundle ist eine gebündelte Version Ihrer CSS-Dateien (ich verwende Webpack). Die Idee besteht darin, all diese script/css-Tags aus Ihrer Indexseite zu entfernen und sie intelligent zu bündeln, sodass Sie genau steuern können, wann und wie sie geladen werden. In diesem Beispiel würden Sie davon ausgehen, dass css.bundle Stile zum Formatieren der Homepage verwendet, während die anderen Skripte geladen werden. Skripte ohne Verzögerung oder asynchrones Tag werden in der Reihenfolge heruntergeladen und ausgewertet, in der Sie sie platziert haben. Also ja, das CSS-Bündel wird hier zuerst geladen, dann wird alles andere verzögert (also async) geladen, aber diese Skripte werden in der angegebenen Reihenfolge evaluieren (ausführen). –

+0

Wenn ich das verstehe, richtig zu verschieben. 'defer' auf' css.bundle' würde die Ausführungsreihenfolge nicht ändern. Ich habe kein Webpack verwendet. Aber ich denke, 'css.bundle' soll' style' Tags hinzufügen und die Styles anhängen. Meine Frage ist, ob 'css.bundle' dann unter' vendor.bundle.js' Downloads vor 'css.bundle.js' erwartet, würde' vendor.bundle' exceuto, bevor CSSOM bereit ist? – user31782

2

DOMContentLoaded kann, bevor CSSOM wird source

Die DOMContentLoaded Ereignis wird ausgelöst, kurz gebrannt werden, nachdem die HTML analysiert; der Browser weiß, dass er JavaScript nicht blockiert und da es keine anderen Parser-Blockierungsskripte gibt, kann die CSSOM-Konstruktion auch parallel ablaufen.

enter image description here

Artikel auf Google Developer beschreibt async statt defer aber im Falle Ihrer Frage, ist es nicht etwas, weil auf Steve Sourders article auf perfplanet

-VERZÖGERUNG Skripte basierend ändern ausführen nach DOM Interaktiv.

und his comment unter seinem Artikel

[...] sagt der spec, dass DEFER Skripte nach domInteractive aber vor domContentLoaded laufen.

Sie können Ihr eigenes Experiment machen, suchen Sie unten Code defer und Timeline

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8"> 
    <title>JS Bin</title> 
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.css"> 
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.3/angular-material.css"> 
</head> 
<body> 
    <h1>App</h1> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.js" defer></script> 
</body> 
</html> 

enter image description here

+0

Ich habe die gleichen Tests mit vielen schweren Stylesheets und nur Inline-Javascript durchgeführt. 'DOMContentLoaded' wurde nach dem Herunterladen der Stylesheets und vor dem Anwenden der Stylesheets (CSSOM ready) ausgelöst. Das bedeutet, _ ohne auf Stylesheets zu warten ..._ MDN bedeutet nicht, ohne Stylesheets herunterzuladen; es bedeutet, ohne Stylesheets anzuwenden. – user31782

+0

Ich bin mir nicht sicher, ob ich Sie richtig verstanden habe, aber Inline-Skripte sollten nach CSSOM ausgeführt werden, nicht vorher. [Was passiert, wenn wir unser externes Skript durch ein Inline-Skript ersetzen? Selbst wenn das Skript direkt in die Seite eingezeichnet ist, kann der Browser es erst ausführen, wenn das CSSOM erstellt wurde. Kurz gesagt, inline-JavaScript ist auch Parser-Blockierung.] (Https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp) – hinok

+0

Hinok, das ist genau das, was ich beobachtet habe. inline javscript wird ausgeführt, bevor CSSOM bereit ist. Ich stellte die Frage hier http://stackoverflow.com/q/42891628/3429430 – user31782

Verwandte Themen