309

HTML ページに JavaScript を含めるには、さまざまな方法があります。次のオプションについて知っています。

  • インライン コードまたは外部 URI からロード
  • <head> または <body> タグに含まれる [ 1 , 2 ]
  • なし、deferまたはasync属性を持たない (外部スクリプトのみ)
  • 静的ソースに含まれるか、他のスクリプトによって動的に追加されます (さまざまな解析状態で、さまざまな方法で)

ハードディスクからの browserscripts、javascript:URIs およびonEvent-attributes [ 3 ] を数えないで、JS を実行するための 16 の代替手段が既にあり、何かを忘れているに違いありません。

私は高速 (並列) 読み込みにはあまり関心がなく、実行順序 (読み込み順序とドキュメントの順序に依存する可能性があります) に興味があります。本当にすべてのケースをカバーする良い(クロスブラウザー)リファレンスはありますか? たとえば、 http ://www.websiteoptimization.com/speed/tweak/defer/はそれらのうちの 6 つだけを扱い、主に古いブラウザーをテストします。

ないのではないかと心配していますが、ここに私の具体的な質問があります。初期化とスクリプトの読み込み用の (外部) ヘッド スクリプトがいくつかあります。次に、本文の最後に 2 つの静的なインライン スクリプトがあります。1 つ目は、スクリプト ローダーが別のスクリプト要素 (外部 js を参照) を本体に動的に追加できるようにします。静的なインライン スクリプトの 2 番目は、追加された外部スクリプトからの js を使用する必要があります。もう一方が実行されたことに依存できますか (そしてその理由:-)?

4

5 に答える 5

397

スクリプトを動的にロードしたり、またはとしてマークしたりしていない場合deferasyncスクリプトはページで検出された順序でロードされます。外部スクリプトであるかインラインスクリプトであるかは関係ありません。ページで検出された順序で実行されます。外部スクリプトの後にあるインラインスクリプトは、それらの前にあるすべての外部スクリプトがロードされて実行されるまで保持されます。

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

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

スクリプトタグが動的に挿入される場合、実行順序がどのように動作するかはブラウザによって異なります。このリファレンス記事でFirefoxの動作を確認できます。一言で言えば、Firefoxの新しいバージョンでは、スクリプトタグが別の方法で設定されていない限り、動的に追加されたスクリプトタグがデフォルトで非同期になります。

のスクリプトタグasyncは、ロードされるとすぐに実行される場合があります。実際、ブラウザはパーサーを他の処理から一時停止して、そのスクリプトを実行する場合があります。したがって、実際にはほとんどいつでも実行できます。スクリプトがキャッシュされている場合、ほとんどすぐに実行される可能性があります。スクリプトのロードに時間がかかる場合は、パーサーの実行後に実行される可能性があります。覚えておくべきことの1つasyncは、いつでも実行でき、その時間は予測できないということです。

のスクリプトタグdeferは、パーサー全体が完了するまで待機してから、でマークされたすべてのスクリプトを検出さdeferれた順序で実行します。これにより、相互に依存する複数のスクリプトをとしてマークすることができますdefer。これらはすべて、ドキュメントパーサーが完了するまで延期されますが、依存関係を維持しながら、検出された順序で実行されます。deferスクリプトがキューにドロップされ、パーサーが完了した後に処理されるように思います。技術的には、ブラウザはいつでもバックグラウンドでスクリプトをダウンロードしている可能性がありますが、パーサーがページの解析とマークされていないインラインスクリプトの解析と実行を完了するまで、パーサーを実行またはブロックしませdeferasync

その記事からの引用は次のとおりです。

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

HTML5仕様の関連部分(新しい準拠ブラウザー用)はここにあります。非同期動作についてはたくさん書かれています。明らかに、この仕様は、動作を判断するためにテストする必要がある古いブラウザ(または不適合なブラウザ)には適用されません。

HTML5仕様からの引用:

次に、状況を説明する次のオプションの最初のオプションに従う必要があります。

要素にsrc属性があり、要素にdefer属性があり、要素に「パーサー挿入」のフラグが付けられていて、要素に非同期属性がない場合要素は 、のリストの最後に追加する必要があります。要素を作成したパーサーのドキュメントに関連付けられたドキュメントの解析が終了したときに実行されるスクリプト。

フェッチアルゴリズムが完了した後にネットワークタスクソースがタスクキューに配置するタスクは、要素の「パーサー実行の準備ができました」フラグを設定する必要があります。パーサーはスクリプトの実行を処理します。

要素にsrc属性があり、要素に「パーサー挿入」のフラグが付けられていて、要素に非同期属性がない場合 要素は、要素を作成したパーサーのドキュメントの保留中の解析ブロックスクリプトです。(このようなスクリプトは、ドキュメントごとに一度に1つしか存在できません。)

フェッチアルゴリズムが完了した後にネットワークタスクソースがタスクキューに配置するタスクは、要素の「パーサー実行の準備ができました」フラグを設定する必要があります。パーサーはスクリプトの実行を処理します。

要素にsrc属性がなく、要素に「パーサー挿入」のフラグが設定されていて、スクリプト要素を作成したHTMLパーサーまたはXMLパーサーのドキュメントに、スクリプトをブロックしているスタイルシートがある場合要素は保留中の解析-要素を作成したパーサーのドキュメントのブロックスクリプト。(このようなスクリプトは、ドキュメントごとに一度に1つしか存在できません。)

要素の「パーサー実行の準備ができました」フラグを設定します。パーサーはスクリプトの実行を処理します。

要素にsrc属性があり、async属性がなく、「force-async」フラグが設定されていない場合要素は、関連付けられたできるだけ早く順番に実行されるスクリプトのリストの最後に追加する必要がありますスクリプトアルゴリズムの準備が開始されたときのスクリプト要素のドキュメントを使用します。

フェッチアルゴリズムが完了した後にネットワークタスクソースがタスクキューに配置するタスクは、次の手順を実行する必要があります。

要素が、上記で追加されたスクリプトのリストの最初の要素ではない場合は、要素を準備完了としてマークしますが、スクリプトをまだ実行せずにこれらの手順を中止します。

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

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

できるだけ早く順番に実行されるこのスクリプトのリストがまだ空でなく、最初のエントリがすでに準備完了としてマークされている場合は、実行というラベルの付いたステップに戻ります。

要素にsrc属性がある場合、スクリプトアルゴリズムの準備が開始されたときに、スクリプト要素のドキュメントをできるだけ早く実行するスクリプトのセットに要素を追加する必要があります。

フェッチアルゴリズムが完了した後にネットワークタスクソースがタスクキューに配置するタスクは、スクリプトブロックを実行してから、できるだけ早く実行されるスクリプトのセットから要素を削除する必要があります。

それ以外の場合、他のスクリプトがすでに実行されている場合でも、ユーザーエージェントはスクリプトブロックをすぐに実行する必要があります。


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

この記事のモジュールスクリプトを含む、スクリプトのさまざまな組み合わせのフェッチと実行を示す非常に便利なタイムラインチャートがあります:JavascriptModuleLoading

于 2012-01-25T01:38:51.393 に答える
16

ブラウザは、スクリプトを見つけた順序で実行します。外部スクリプトを呼び出すと、スクリプトがロードされて実行されるまでページがブロックされます。

この事実をテストするには:

// file: test.php
sleep(10);
die("alert('Done!');");

// HTML file:
<script type="text/javascript" src="test.php"></script>

動的に追加されたスクリプトは、ドキュメントに追加されるとすぐに実行されます。

この事実をテストするには:

<!DOCTYPE HTML>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <script type="text/javascript">
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.src = "link.js"; // file contains alert("hello!");
        document.body.appendChild(s);
        alert("appended");
    </script>
    <script type="text/javascript">
        alert("final");
    </script>
</body>
</html>

アラートの順序は「追加」->「こんにちは!」です。->「最終」

スクリプトでまだ到達していない要素にアクセスしようとすると(例<script>do something with #blah</script><div id="blah"></div>:)、エラーが発生します。

全体として、はい、外部スクリプトを含めて、それらの関数と変数にアクセスできますが、現在の<script>タグを終了して新しいタグを開始する場合に限ります。

于 2012-01-25T01:42:27.910 に答える