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

[解決済み】スクリプトの読み込みと実行順序について

2022-04-16 04:14:26

質問

htmlページにJavaScriptを含めるには、実に様々な方法があります。私は以下の方法について知っています。

  • インラインコードまたは外部URIからの読み込み
  • alt;head>または <body> タグに含まれている [... 1 , 2 ]
  • ない defer または async 属性 (外部スクリプトのみ)
  • 静的なソースに含まれるか、他のスクリプトによって動的に追加される(異なるパース状態、異なるメソッドで)。

ハードディスクからのブラウザースクリプト、javascript:URIはカウントしていません。 onEvent -属性 [ 3 ]、JSを実行させるための代替案がすでに16個もあり、何か忘れていることがあるはずです。

高速(並列)読み込みにはあまりこだわらず、実行順序(読み込み順序に依存するかもしれませんし ドキュメントオーダー ). はあるのでしょうか? (クロスブラウザ) 本当にすべてのケースをカバーするリファレンスはありますか? http://www.websiteoptimization.com/speed/tweak/defer/ は6つしか扱わず、ほとんど古いブラウザでテストしています。

ないのが怖いので、以下、具体的な質問です。初期化とスクリプトのロードのために、いくつかの(外部の)ヘッドスクリプトを持っています。そして、本文の最後に2つの静的なインライン・スクリプトがあります。最初のスクリプトは、スクリプト・ローダーが別のスクリプト要素(外部jsを参照)を動的にボディに追加するためのものです。2つ目の静的インライン・スクリプトは、追加された外部スクリプトのjsを使いたいと考えています。もう一方のスクリプトが実行されたことに依存できるでしょうか?

解決方法は?

スクリプトを動的にロードしていない場合、またはスクリプトを defer または async の場合、スクリプトはページ内で遭遇した順番に読み込まれます。 外部スクリプトかインラインスクリプトかは関係なく、ページ内で遭遇した順番に実行されます。 外部スクリプトの後にあるインラインスクリプトは、その前にあるすべての外部スクリプトがロードされて実行されるまで保持されます。

非同期スクリプトは(非同期として指定された方法に関係なく)予測できない順序でロードされ、実行されます。 ブラウザはこれらを並列に読み込み、好きな順序で自由に実行します。

複数の非同期なものの間に予測可能な順序はありません。 もし予測可能な順序が必要なら、非同期スクリプトからのロード通知に登録し、適切なものがロードされたときに手動でjavascriptコールをシーケンスすることによってコード化する必要があります。

scriptタグが動的に挿入される場合、実行順序がどうなるかはブラウザに依存します。 Firefoxがどのように動作するかは この参考記事 . 簡単に言うと、Firefox の新しいバージョンでは、動的に追加された script タグは、script タグが他に設定されていない限り、async にデフォルトで設定されます。

スクリプトタグに async は、読み込まれるとすぐに実行されるかもしれません。 実際、ブラウザはパーサーが他に何をしていたとしても、それを一時停止してそのスクリプトを実行することができます。 つまり、ほとんどいつでも実行できるのです。 スクリプトがキャッシュされている場合は、ほとんど即座に実行されるかもしれません。 スクリプトの読み込みに時間がかかる場合は、パーサが終了した後に実行されるかもしれません。 覚えておくべきことは async は、いつでも実行可能であり、その時間は予測不可能であるということです。

スクリプトタグに defer は、パーサ全体が終了するまで待ち、それから defer を発生した順に表示します。 このため、互いに依存する複数のスクリプトを defer . これらはすべて、ドキュメントパーサーが終了するまで延期されますが、依存関係を維持したまま発生した順番に実行されます。 私が考えるに defer のように、スクリプトはパーサが終了した後に処理されるキューに落とされます。 技術的には、ブラウザはバックグラウンドでいつでもスクリプトをダウンロードできますが、パーサーがページの解析を完了し、マークされていないインライン スクリプトを解析して実行するまで、スクリプトは実行されず、パーサーもブロックされません。 defer または async .

その記事からの引用です。

<ブロッククオート

挿入されたスクリプトは、IEとWebKitでは非同期で実行されますが Operaと4.0以前のFirefoxでは、同期的に動作します。

HTML5仕様の該当部分(新しい対応ブラウザ用)は ここで . そこには、非同期動作について多くのことが書かれています。 明らかに、この仕様は古いブラウザ(または不適合なブラウザ)には適用されず、その動作はおそらくテストしなければ判断できません。

HTML5仕様書からの引用です。

<ブロッククオート

そして、その状況を説明する以下のオプションのうち、最初のものを選びます。 に従わなければならない。

要素にsrc属性があり、その要素にdefer 属性があり、その要素が "パーサ挿入済み" としてフラグが立てられており、かつ 要素にasync属性がないこと この要素は が実行されるときに実行されるスクリプトのリストの最後に追加されます。 を実行したパーサーのドキュメントに関連するパージングが終了しました。 要素を作成しました。

ネットワーク・タスク・ソースがタスク・キューに入れるタスクは、いったん フェッチアルゴリズムが完了したら、その要素の "準備完了を設定する必要があります。 フラグを立てます。パーサーはスクリプトの実行を処理します。

要素にsrc属性があり、その要素にフラグが立っている場合 として、その要素はasync属性を持っていません。 この要素は、保留中の解析ブロックスクリプトのDocumentの その要素を作成したパーサー (そのようなパーサーは1つだけです。 スクリプトを使用します)。

ネットワーク・タスク・ソースがタスク・キューに入れるタスクは、いったん フェッチアルゴリズムが完了したら、その要素の "準備完了を設定する必要があります。 フラグを立てます。パーサーはスクリプトの実行を処理します。

要素にsrc属性がなく、かつその要素が パーサー挿入フラグが立っていて、HTMLパーサーのドキュメントまたは script 要素を作成した XML パーサーは、そのスタイルシートが ブロックスクリプト この要素は、保留中の解析ブロックスクリプトの その要素を作成したパーサーのドキュメント。(ただし このようなスクリプトは、1つのDocumentにつき、同時に1つだけです)。

要素の "ready to be parser-executed" フラグを設定します。パーサーは はスクリプトの実行を処理します。

要素にsrc属性があり、async属性がない場合。 そして、"force-async" フラグが設定されていません。 その要素は を順番に実行するスクリプトのリストの末尾に追加します。 その時点のscript要素のDocumentに関連する可能な限り は、prepare a script アルゴリズムが開始されたときです。

ネットワーク・タスク・ソースがタスク・キューに入れるタスクは、一旦 は、フェッチアルゴリズムが完了すると、次のステップを実行する必要があります。

その要素が、現在、スクリプトのリストの最初の要素でない場合 に追加され、できるだけ早く順番に実行されます。 上記の の場合、その要素を準備完了としてマークしますが、このステップを中断します。 はまだスクリプトを実行しません。

実行します。最初のスクリプトに対応するスクリプトブロックを実行します。 このスクリプトのリストの中で、順番に実行されるスクリプトの要素で、できるだけ早く となります。

このスクリプトのリストから、最初の要素を削除します。 をできるだけ早く順番に表示します。

この「できるだけ早く順番に実行されるスクリプト」のリストが がまだ空でなく、最初のエントリがすでに をクリックすると、実行と書かれたステップにジャンプバックします。

要素にsrc属性がある場合 その要素を のできるだけ早く実行されるスクリプトのセットです。 スクリプトのアルゴリズムが準備された時点で、script 要素の が開始されました。

ネットワーク・タスク・ソースがタスク・キューに入れるタスクは、一旦 フェッチアルゴリズムが完了したら、そのスクリプトブロックを実行し、さらに その後、実行されるスクリプトのセットからその要素を削除する。 をなるべく早く実行する。

その他 ユーザーエージェントは、直ちにスクリプトブロックを実行しなければならない。 他のスクリプトが既に実行されている場合であっても。


Javascriptのモジュールスクリプトはどうなっているのか。 type="module" ?

Javascriptでは、以下のような構文でモジュールの読み込みをサポートするようになりました。

<script type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Modules are pretty cool.');
</script>

または src 属性で指定します。

<script type="module" src="http://somedomain.com/somescript.mjs">
</script>

を含むすべてのスクリプトは type="module" は自動的に defer 属性で指定します。 これは、ページの他の読み込みと並行して(インラインでない場合)それらをダウンロードし、順番に、しかしパーサーが終了した後に実行されます。

また、モジュールスクリプトには async 属性は、パーサが終了するまで待たず、インラインモジュールスクリプトをできるだけ早く実行します。 async スクリプトを他のスクリプトと相対的に特定の順序で実行します。

この記事の中に、モジュールスクリプトを含む様々なスクリプトの組み合わせのフェッチと実行を示す、かなり便利なタイムラインチャートがあります。 Javascriptモジュールのロード .