web-dev-qa-db-ja.com

DOMContentLoadedイベントの前に遅延スクリプトが実行されますか?

Attirbuteを延期すると MDNは言います

このブール属性は、ドキュメントが解析された後にスクリプトが実行されることをブラウザに示すように設定されていますが、before DOMContentLoadedです。 defer属性は、外部スクリプトでのみ使用する必要があります。

DOMContentLoadedについて MDNも言う

DOMContentLoadedイベントは、最初のHTMLドキュメントが完全に読み込まれ、解析されたときにスタイルシートの待機 ...なしで発生します.

したがって、DOMContentLoadedが準備される前にCSSOMが呼び出されます。つまり、CSSOMの準備が整う前に、遅延スクリプトが実行されます。しかし、それがtrueの場合、スクリプトは正しいcssプロパティ値を取得できず、cssを正しく適用できません。しかし、それは真実ではありません。延期されたすべてのスクリプトがうまく機能することはわかっています。

  1. それでは、MDNのドキュメントは技術的に正しくありませんか?
  2. DOMContentLoaded`の公式ドキュメントはどこにありますか? https://dom.spec.whatwg.org/ で検索しましたが、見つかりませんでした。

PS:しないでください グーグルは言います CSSOMはインラインジャバスクリプトを実行する前にビルドされる

enter image description here

しかし、グーグルは技術的に正しくありません。 CSSOMの準備が整う前にインラインJavaScriptが実行されます。そして、私のテストから、MDNが正しいことがわかり、jsファイル(遅延と非遅延の両方)がcssファイル(またはjsがインライン)の前にダウンロードされると、CSSOMの準備が整う前にjsが実行されます。したがって、jsはスタイルを正しく処理しない可能性があります。これを回避するには、すべてのjsロジックの前に強制リフローが必要です。

したがって、ユーザーがすべてのjsが既にキャッシュされており、cssがキャッシュされていないWebサイトにアクセスした場合、OR jsがcssの前にダウンロードされると、誤ってレンダリングされたページが表示される可能性があります。すべてのウェブサイトのjsファイルでリフローします。

19
user31782

DOMContentLoadedはCSSOMの前に起動できます source

DomContentLoadedイベントは、HTMLが解析された直後に発生します。ブラウザはJavaScriptでブロックしないことを認識しており、他のパーサーブロックスクリプトがないため、CSSOMの構築も並行して実行できます。

enter image description here

Google Developerの記事では、asyncではなくdeferについて説明していますが、質問の場合は Steve Sourdersの記事 に基づいているため、何も変更されません perfplanet

DEFERスクリプトは、DOM Interactiveの後に実行されます。

そして 彼のコメント 彼の記事の下

[...]仕様によると、DEFERスクリプトはdomInteractiveの後でdomContentLoadedの前に実行されます。

独自の実験を行うことができます。deferとタイムラインを使用したコードを以下で確認してください

<!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

5
hinok

遅延スクリプト読み込みを使用しています。有名なウェブサイトのパフォーマンスの第一人者であるある人からの長い技術的な説明がありました。彼は据え置きが進むべき道であることを明確に述べています(これとその技術的理由のために、あらゆる種類のデータとチャートに裏付けられて、多くの人々が議論のために広く開かれていると感じたようです、非同期:)。

だから私はそれで働き始めました。延期されたスクリプトには、非同期でダウンロードするという利点がありますが、表示された順序で実行されるため、非同期の問題になる可能性があります(たとえば、次のように言って非同期スクリプトの実行順序を制御しないため、ベンダーバンドルの前にアプリバンドルをロードできます) 「この順序で」)。

ただし、これで問題は解決しますが、バンドルの取得方法によっては、CSSバンドルが読み込まれていない可能性があることをすぐにわかりました。そのため、設定方法によっては、スタイルのないコンテンツになる可能性があります。延期のために、それらはまた、それらのスクリプトでdomなどに書き込むべきではないと言っていることに注意してください(これもドキュメントの観点からは理にかなっています)。

だからあなたのドキュメントは正しいようです。効果は簡単に再現されます。

どうすればそれから抜け出すことができますか。最も基本的な方法は次のとおりです:

<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>

これにより、CSSが最初に読み込まれるようになり、ホームページなどが適切に表示され、(3つすべてが非同期で読み込まれていても)app.bundleが最後に実行され、他のすべての依存関係が確実に順守されるようになります。

そのため、アプリをキックオーバーするために必要な最低限のCSSを最低限必要とし、それをバンドルとして作成し、まず何よりも先にロードします。それ以外の場合は、モジュール/コンポーネントごとにCSSをバンドルできます。

このトピックにはもっと多くのことがあり、私はおそらくもっと多くのことをすることができますが、もう一度(参照を見つけようとします)、これはそのパフォーマンスウィザードによってあからさまに推奨されたので、試してみましたが、かなり効果的であるようです。

編集:魅力的で、その参照(まだ見つけていません)を探している間、私はそのテーマについて「専門家」をいくつか調べました。推奨事項は大きく異なります。非同期はあらゆる面ではるかに優れていると言う人もいれば、延期する人もいます。審査員は本当にこのトピックについて考えているようですが、全体として、スクリプトを構築する方法と正確に関係するのは、実際にどちらが優れているかというよりも、おそらく関係があると思います。

もう一度編集します。ここにいくつかの証拠があります。上記の単純な読み込みシーケンスを使用してスタブWebサイトでパフォーマンスアナライザーを実行し、スクリプトを意図的に単純にして、タイムラインに表示されるようにしました。

これが結果のSSです。ここには4つの黄色のボックスがあります。最初の3つはスクリプトの評価です。 4番目のイベント(ツールでマウスカーソルを合わせると、これはSSの記憶です)は、DOMContentLoadedイベント(赤い角のイベント)です。

Scripts loading/evaluating before DOMContentLoaded event

4
Tim Consolazio

実際には仕様を読みませんでした。以下は、Chrome(Chromium 68、Ubuntuで確認)の実際の動作に基づいています。動作はブラウザによって異なる場合があります。 、仕様で未定義の場合。たとえば2010年 スクリプトはスタイルシートの処理を常に待機するわけではありません 。Iassume合意は達成され、行動は長年にわたって標準化されてきました。


deferスクリプトは、domInteractiveの後、domContentLoadedの前に実行されます。シーケンシャルです。

domInteractivedomContentLoadedは、2つのタイムスタンプで、Chrome devtools 'Performance(以前のTimeline))タブで表示できます。他の同様のツールでもおそらく表示されますが、試していません。

domInteractiveは、HTML解析と初期DOM構築が終了した時点(およびすべての「同期」スクリプトの実行が終了した時点)です。 document.readyStateからの変更'loading''interactive'; readystatechangeイベントは、それに応じてdocumentで発生します。

deferスクリプトはすべて、出現順に実行されます。次にdomContentLoadedが来ます。DOMContentLoadedイベントはdocumentで発生します。

DOMとCSSOMの構築は互いに依存しません。ただし、同期スクリプトによって依存関係が生じる場合があります。

内部または外部の各同期スクリプトは、precedingスタイルシートが解析されるのを待ちます(もちろん、フェッチ後)。

はい、同期スクリプトは後続スタイルシートによってブロックされません。 MDNとGoogleおよび他の記事は、「スクリプトは準備が整っているCSSOMに依存している」と述べています。彼らは(おそらく)前の部分だけが依存していることについては言及しませんでした。

PS:グーグルは、インラインJAVScriptを実行する前にCSSOMがビルドされると言ってはいけません

グーグルはそれを言わなかった(少なくとも、私がこの記事を読んだ時点では)。

逆に、1つの同期スクリプトが(外部の場合)フェッチされて実行されるまで、それに続くコード、HTML、スタイルシート、またはその他のスクリプトは、解析/実行/構築できません。彼らは彼らに続くすべてのものをブロックします。

したがって、特定のケースでは、同期スクリプトがないと、DOMContentLoadedイベントが発生する可能性がありますbefore or after CSSOMの準備ができています。それがMDNが「スタイルシートを待たずに」と言うことの意味です。

defer/asyncスクリプトはスタイルシートをまったく気にしません。

同期スクリプトとは異なり、defer/asyncスクリプトは、先行するスタイルシートを待機せず、後続のスタイルシート/スクリプトもブロックしません。それらはそれらの「依存チェーン」から完全に削除されます。解析されている進行中のスタイルシートに依存することはできません。

defer/asyncの違い:

  • 上記のように、deferスクリプトにはpredictable実行時間があります。 DOMは準備ができています。また、順番に実行することが約束されています。

    Update:deferスクリプトがリストのendに追加されると言います W3Cの仕様(20番目の項目)defer scripts are added to the end of the list, said W3C's spec
    WHATWGの仕様でも

  • asyncスクリプトは実行順序を保証していません。各asyncスクリプトは、フェッチされるとすぐに「実行待ち」になります。レンダリングプロセスがアイドル状態になると、それらが実行されます。 (正確には、リソースのタイプによって優先順位は異なります。 仕様 は貴重な要件を提供します)

これらは hinokの2つの例 、前者のasync(Googleから)および後者のdeferを十分に説明しているはずです。


ページの読み込み時にCSSOMを使用した経験があまりない(ただし、ページの読み込み時にDOMを操作している)ため、信頼できるアドバイスを提供することはできません。 「loadでのwindowイベント」または「早期にリフローを強制」が機能するようです。

3
Kevin SHI