ホームページ > 記事 > ウェブフロントエンド > スクリプトタグの defer 属性と async 属性の簡単な分析
1. はじめに
私が見た先輩のコードは以下の通りです
<script src="#link("xxxx/xx/home/home.js")" type="text/javascript" async defer></script>
予想外に、先輩ドライバーの何らかのブラックテクノロジーに違いないと思いました。この 2 つが一緒になると、魔法のような化学反応が起きるのではないでしょうか。そこで私は敬虔な心で本や資料をざっとめくり、まずそれぞれの定義を確認しました。
次に、いくつかの調査を行います
まず、async と defer の定義を見てみましょう。Red Book Telescope を開くと、次のように紹介されています
2.1 defer
この属性の目的は、スクリプトはページの構造には影響しません。つまり、スクリプトは、実行前にページ全体が解析されるまで遅延されます。したがって、<script> 要素に defer 属性を設定することは、ブラウザにすぐにダウンロードするが実行を遅らせるように指示することと同じです。 </script>
HTML5 仕様では、スクリプトは出現順に実行する必要があるため、最初の遅延スクリプトは 2 番目の遅延スクリプトの前に実行され、これら 2 つのスクリプトは DOMContentLoaded イベントの前に実行されます。実際には、遅延スクリプトは必ずしも順番に実行されるわけではなく、DOMContentLoad 時間がトリガーされる前に実行される必要もないため、遅延スクリプトは 1 つだけ含めることをお勧めします。
2.2 async
この属性は defer に似ており、処理スクリプトの動作を変更するために使用されます。また、遅延と同様に、async は外部スクリプト ファイルに対してのみ機能し、ブラウザーにファイルをすぐにダウンロードするように指示します。ただし、遅延とは異なり、非同期とマークされたスクリプトは、その順序で実行されることが保証されません。
2 番目のスクリプト ファイルは、最初のスクリプト ファイルより前に実行される場合があります。したがって、この 2 つが相互に依存していないことを確認することが重要です。 async 属性を指定する目的は、ページが 2 つのスクリプトのダウンロードと実行を待機して、ページの他のコンテンツが非同期で読み込まれるのを防ぐことです。
要約すると、これら 2 つの属性によりスクリプト タグが非同期で読み込まれますが、実行のタイミングが異なります。セグメントフォールトの回答からの画像の引用
青い線はネットワーク読み取りを表し、赤い線は実行時間を表し、両方ともスクリプト用です。緑の線は HTML 解析を表します。
つまり、async は順不同ですが、defer は順番に実行されます。これにより、他のスクリプトに依存しない Baidu Analytics や Google Analytics などのライブラリには async がより適していると判断されます。この図から、通常の <script> タグの読み込みと解析が同期していることがわかります。これが、<body> の最後に <script> を記述する理由です。まず、リソースの読み込みによって発生する長時間の白画面を防ぐため、もう 1 つの理由は、js が DOM 操作を実行する可能性があるため、すべての DOM がレンダリングされた後に実行する必要があることです。 </script>
2.3って本当ですか?
ただし、この図 (Baidu で見つかったほぼ唯一の答え) は厳密なものではなく、これは単なる標準的な状況であり、ほとんどのブラウザーは実装時に最適化を行います。
Chrome がどのように動作するかを見てみましょう
「WebKit Technology Insider」:
1. ユーザーが Web ページの URL を入力すると、WebKit はそのリソース ローダーを呼び出して、その URL に対応する Web ページをロードします。
2. ローダーはネットワーク モジュールに依存して接続を確立し、リクエストを送信し、応答を受信します。
3. WebKit はさまざまな Web ページまたはリソースからデータを受け取りますが、その一部は同期または非同期で取得される場合があります。
4. Web ページは HTML インタプリタに渡され、一連の単語 (トークン) に変換されます。
5. インタプリタは単語に基づいてノード (Node) を構築し、DOM ツリーを形成します。
6. ノードが JavaScript コードの場合、JavaScript エンジンを呼び出して解釈して実行します。
7. JavaScript コードは DOM ツリーの構造を変更する場合があります。
8. ノードが画像、CSS、ビデオなどの他のリソースに依存する必要がある場合は、リソースローダーを呼び出してそれらをロードしますが、それらは非同期であり、現在の DOM ツリーの継続的な作成を妨げません。 ; JavaScript リソース URL の場合 (非同期モードをマークしない場合)、DOM ツリーの作成を続行する前に、JavaScript リソースが JavaScript エンジンによってロードされて実行されるまで、現在の DOM ツリーの作成を停止する必要があります。
したがって、一般的に言えば、Chrome ブラウザは最初に HTML ドキュメントをリクエストし、次にその中のさまざまなリソースに対応するリソース ローダーを呼び出して非同期ネットワーク リクエストを行い、同時に タグ この時点で、メイン プロセスはレンダリングを停止し、リソースがロードされるのを待ってから、V8 エンジンを呼び出して js を解析し、DOM 解析を続行します。私の理解では、async 属性を追加することは、独立してロードして実行するために別のプロセスを開くことと同等であり、defer は
の最後に <script> を配置するのと同じ効果があります。 <p>3. 実験1<br/><p>3.1デモ<p>上記の結論を検証するために、テストしてみましょう<pre class="brush:html;toolbar:false"><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.css" rel="stylesheet"> <link href="http://cdn.staticfile.org/foundation/6.0.1/css/foundation.css" rel="stylesheet"> <script src="http://lib.sinaapp.com/js/angular.js/angular-1.2.19/angular.js"></script> <script src="http://libs.baidu.com/backbone/0.9.2/backbone.js"></script> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script> </head> <body> ul>li{这是第$个节点}*1000 </body> </html></pre><p> <p><p>さまざまな CDN から 2 つの CSS と 3 つの JS を引用し、本文に 1000 li を作成する簡単なデモ。 Chrome のタイムラインを使用して、外部参照リソースの場所を調整し、関連する属性を追加して検証します。 <p>3.2 <head>に配置されます<p><img src="https://img.php.cn//upload/image/696/384/898/1480744154246530.jpg" title="1480744154246530.jpg" alt="スクリプトタグの defer 属性と async 属性の簡単な分析"/><p>リソースを非同期で読み込みますが、<body>のレンダリングをブロックし、白い画面が表示されます<p>3.3 の下部に配置されます。 <body><p> <img src="https://img.php.cn//upload/image/639/130/331/1480744171245752.jpg" title="1480744171245752.jpg" alt="スクリプトタグの defer 属性と async 属性の簡単な分析"/><p> リソースを非同期でロードし、<body> のコンテンツがレンダリングされてロードされるのを待ち、JS を順番に実行します<p>3.3 <head> ヘッダーに配置して async を使用します<p> <img src="https://img.php.cn//upload/image/392/809/508/1480744186346776.jpg" title="1480744186346776.jpg" alt="スクリプトタグの defer 属性と async 属性の簡単な分析"/><p> リソースを非同期でロードし、JS リソースは順番ではなく完了後にすぐに実行されます<p>3.4 <head> に配置して defer を使用します<p><img src="https://img.php.cn//upload/image/414/954/733/1480744198930605.jpg" title="1480744198930605.jpg" alt="スクリプトタグの defer 属性と async 属性の簡単な分析"/><p>リソースを非同期でロードし、DOM がレンダリングされた後に JS を順番に実行します <p>3.5 それを <head> ヘッドに配置し、async と defer を同時に使用します<p><img src="https://img.php.cn//upload/image/312/914/529/1480744214244130.jpg" title="1480744214244130.jpg" alt="スクリプトタグの defer 属性と async 属性の簡単な分析"/><p> パフォーマンスは async と一致します。心を開いて、これら 2 つの属性の位置を交換して、オーバーレイ効果があるかどうかを確認しました。結果は一貫していることがわかりました。<p> 要約すると、Webkit エンジンでは、依然として推奨される方法です。 Baidu Google Analytics や Bulianzi などの独立したライブラリを使用する必要がある場合は、<script> を <head> に記述します。 ; ヘッダーでは defer 属性を使用できます。互換性とは何ですか? <p> caniuse では、IE<=9 では非同期がサポートされていますが、他のブラウザーではサポートされています。バグですが、他のブラウザでは問題ありません。この現象はこの問題の説明にあります。このため、「Telescope」で遅延を 1 つだけにすることが推奨されます。したがって、両方の属性は、非同期がサポートされていない場合に defer を有効にするように指定されていますが、場合によっては defer に依然としてバグがあります。 <br/> async 属性が指定されている場合でも defer 属性を指定すると、遅延のみをサポートする (非同期ではなく) レガシー Web ブラウザーがデフォルトの同期ブロック動作ではなく遅延動作にフォールバックすることがあります。<p> 5. 結論<p><p>実際、最も安全な方法は、<body> の下部に <script> を記述することです。互換性の問題、白い画面の問題、実行順序の問題は発生しません。現時点では、Firefox と IE のレンダリング メカニズムのみを研究しており、画像、CSS、その他の外部リソースのレンダリングについては引き続き研究する必要があります。研究される。 <p><br/></script>