1. ホーム
  2. ジャバスクリプト

[解決済み】Webページの読み込みと実行の順序は?

2022-04-03 19:04:34

質問

私はいくつかのWebベースのプロジェクトを行ってきましたが、普通のWebページのロードと実行のシーケンスについてはあまり考えていません。しかし、今私は詳細を知る必要があります。GoogleやSOから答えを見つけるのは難しいので、この質問を作りました。

サンプルページはこのようなものです。

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

では、ここからが質問です。

  1. このページはどのように読み込まれるのですか?
  2. 読み込みの順序は?
  3. JSコードはいつ実行されますか?(インラインと外部)
  4. CSSはいつ実行(適用)されますか?
  5. $(document).readyはいつ実行されるのか?
  6. abc.jpgはダウンロードされるのでしょうか?それともkkk.pngがダウンロードされるだけでしょうか?

私は以下のように理解しています。

  1. ブラウザは、最初にhtml(DOM)を読み込みます。
  2. ブラウザは外部リソースの読み込みを上から下へ、一行ずつ開始します。
  3. もし <script> を満たした場合、読み込みはブロックされ、JSファイルの読み込みと実行が完了するまで待機し、その後続行します。
  4. 他のリソース(CSS/画像)は並行して読み込まれ、必要に応じて実行されます(CSSのように)。

それとも、こんな感じでしょうか。

ブラウザはhtml(DOM)を解析し、外部リソースを配列またはスタック状の構造体として取得する。htmlが読み込まれると、ブラウザは構造体内の外部リソースを並列に読み込んで実行し始め、すべてのリソースを読み込むまで続ける。そして、JSによってユーザーの行動に対応したDOMに変更される。

htmlページのレスポンスがあった時の詳しい説明をどなたかお願いします。これはブラウザによって異なるのでしょうか?この質問について何か参考資料があれば教えてください。

ありがとうございます。

EDITです。

FirefoxでFirebugで実験してみました。そして、以下の画像のように表示されました。

解決方法は?

サンプルによると

<html>
 <head>
  <script src="jquery.js" type="text/javascript"></script>
  <script src="abc.js" type="text/javascript">
  </script>
  <link rel="stylesheets" type="text/css" href="abc.css"></link>
  <style>h2{font-wight:bold;}</style>
  <script>
  $(document).ready(function(){
     $("#img").attr("src", "kkk.png");
  });
 </script>
 </head>
 <body>
    <img id="img" src="abc.jpg" style="width:400px;height:300px;"/>
    <script src="kkk.js" type="text/javascript"></script>
 </body>
</html>

大まかな実行の流れは以下のようになります。

  1. HTMLドキュメントがダウンロードされる
  2. HTMLドキュメントのパースが始まる
  3. HTMLパース到達 <script src="jquery.js" ...
  4. jquery.js がダウンロードされ、パースされる
  5. HTMLパース到達 <script src="abc.js" ...
  6. abc.js がダウンロードされ、パースされ、実行される
  7. HTMLパース到達 <link href="abc.css" ...
  8. abc.css がダウンロードされ、パースされる
  9. HTMLパース到達 <style>...</style>
  10. 内部CSSルールが解析され定義される
  11. HTMLパース到達 <script>...</script>
  12. 内部Javascriptが解析され実行される
  13. HTMLパース到達 <img src="abc.jpg" ...
  14. abc.jpg がダウンロードされ、表示されます。
  15. HTMLパース到達 <script src="kkk.js" ...
  16. kkk.js がダウンロードされ、パースされ、実行される
  17. HTMLドキュメントのパース終了

ブラウザの動作により、ダウンロードが非同期かつノンブロッキングになる可能性があることに注意してください。例えば、Firefoxでは、ドメインごとに同時リクエスト数を制限する設定があります。

また、コンポーネントがすでにキャッシュされているかどうかによって、近い将来のリクエストでコンポーネントが再び要求されない場合があります。コンポーネントがキャッシュされている場合、コンポーネントは実際のURLの代わりにキャッシュから読み込まれます。

パースが終了し、ドキュメントの準備が整い読み込まれると、イベント onload が発生します。したがって onload が発行されると $("#img").attr("src","kkk.png"); が実行されます。だから

  1. Documentが準備でき、onloadが実行される。
  2. Javascriptの実行ヒット $("#img").attr("src", "kkk.png");
  3. kkk.png がダウンロードされ #img

$(document).ready() イベントは、実際にはすべてのページコンポーネントがロードされ、準備が整ったときに発行されるイベントです。それについてもっと読む。 http://docs.jquery.com/Tutorials:Introducing_$(document).ready()

編集 - この部分は、並列か否かの部分についてより詳しく説明しています。

デフォルトでは、そして私の理解では、ブラウザは通常3つの方法で各ページを実行します。HTMLパーサー、Javascript/DOM、そしてCSSです。

HTMLパーサーは、マークアップ言語の解析と解釈を担当するため、他の2つのコンポーネントを呼び出すことができなければなりません。

例えばパーサーがこのような行に出くわしたとき。

<a href="#" onclick="alert('test');return false;" style="font-weight:bold">a hypertext link</a>

パーサーは3回呼び出しを行い、2回はJavascriptに、1回はCSSに呼び出しを行います。まず、パーサーはこの要素を作成し、この要素に関連するすべての属性とともに DOM ネームスペースに登録します。次に、パーサーは onclick イベントをこの特定の要素にバインドするために呼び出します。最後に、この特定の要素に CSS スタイルを適用するために、CSS スレッドに再度呼び出しを行います。

実行はトップダウンでシングルスレッドです。Javascriptはマルチスレッドに見えるかもしれませんが、実はシングルスレッドなのです。このため、外部のjavascriptファイルを読み込むと、メインのHTMLページの解析が中断されます。

しかし、CSSファイルは常にCSSルールが適用されているため、同時にダウンロードすることができます。つまり、要素は常に最も新しいCSSルールで再描画されるため、ブロックされないのです。

要素はパースされて初めてDOMで利用可能になります。したがって、特定の要素で作業する場合、スクリプトは常にウィンドウのオンロードイベントの後、またはその中に置かれます。

このようなスクリプトは(jQueryでは)エラーになります。

<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>
<div id="mydiv">Hello World</div>

なぜなら、スクリプトがパースされるときに #mydiv 要素がまだ定義されていません。代わりにこうすればうまくいくでしょう。

<div id="mydiv">Hello World</div>
<script type="text/javascript">/* <![CDATA[ */
  alert($("#mydiv").html());
/* ]]> */</script>

または

<script type="text/javascript">/* <![CDATA[ */
  $(window).ready(function(){
                    alert($("#mydiv").html());
                  });
/* ]]> */</script>
<div id="mydiv">Hello World</div>