2012-01-25 20 views
194

JavaScriptをHTMLページに組み込む方法は非常に多くあります。私は、次のオプションについて知っている:スクリプトのロードと実行の順序

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

javascript:URIsとonEvent - 属性[3]というハードディスクのブラウザスクリプトには数えられていませんが、すでにJSを実行するための16の選択肢があり、忘れてしまったと思います。

私は高速(並列)読み込みには関心がありません。実行順序(読み込み順序やdocument orderによって異なる場合があります)についてもっと興味があります。 本当にすべてのケースをカバーする(クロスブラウザ)の参考資料はありますか?など。 http://www.websiteoptimization.com/speed/tweak/defer/はそのうちの6つしか処理せず、ほとんどの場合古いブラウザをテストします。

私は心配していますが、ここに私の具体的な質問があります:初期化とスクリプトの読み込みのためのいくつかの(外部の)頭部スクリプトがあります。その後、私は体の最後に2つの静的なインラインスクリプトを持っています。最初のスクリプトローダーは、別のスクリプト要素(外部jを参照)を動的に本文に追加することができます。 2番目の静的インラインスクリプトは、追加された外部スクリプトからjsを使用します。他の人が実行されたことに頼ることができますか(なぜですか?)

+0

Steve Soudersの[Blocking Without Scripting](https://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/)を見ましたか?これはちょっと古いものですが、特定のスクリプト読み込みテクニックがあれば、ブラウザの振る舞いについての貴重な洞察がまだ含まれています。 –

答えて

239

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

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

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

スクリプトタグを動的に挿入すると、実行順序はブラウザによって異なります。 Firefoxがどのように動作するかは、this reference articleで確認できます。要するに、新しいバージョンのFirefoxでは、スクリプトタグが設定されていない限り、動的に追加されたスクリプトタグが非同期にデフォルト設定されています。

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

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

スクリプトを挿入するスクリプトがIEとのWebKitで非同期に実行しますが、 :

は、ここでその記事からの引用です。

HTML5仕様(より新しい準拠のブラウザ用)の関連部分はhereです。そこには、非同期動作について書かれたものがたくさんあります。明らかに、この仕様は、決定するためにおそらくテストする必要のある古いブラウザ(または誤って確認しているブラウザ)には適用されません。

HTML5仕様からの引用:

その後、状況 を説明し、次のオプションの最初に従わなければなりません:要素は、src属性、および要素を持っている

場合要素が「パーサーが挿入された」とフラグされており、 要素に非同期属性がありません 要素はスクリプトのリストの最後に を追加する必要がありますハットは、文書 が、 がその要素を作成したパーサーの文書に関連する解析を終了したときに実行される。

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

要素は、src属性を持ち、かつ要素として フラグを設定されている場合は、「パーサ挿入」、および要素が 要素は、ドキュメントの保留解析・ブロッキングスクリプトである非同期属性を持っていません の要素を作成したパーサー。 (一度に文書ごとに、そのような スクリプトが存在する場合があります。)

タスクキュー上のネットワーキング・タスクソースの場所は、かつてparser-こと の要素の」準備を設定する必要がありますフェッチアルゴリズムが完了した というタスク実行された "フラグ。パーサーはスクリプトの実行を処理します。

要素は、src属性を持っていない、と要素が は、「パーサ挿入」としてフラグ付けされており、HTMLパーサまたはスクリプト要素を作成し XMLパーサーのドキュメントは、そのスタイルシートを持っている場合 ブロックスクリプト要素は、要素を作成したパーザのドキュメント の保留中の解析ブロックスクリプトです。 ( は、一度に1つのドキュメントにつき1つのスクリプトにすることができます)。

要素の「実行可能なパーサー実行済み」フラグを設定します。パーサーは スクリプトの実行を処理します。要素は、src属性を持っている場合

、 を非同期属性を持っていないと、「強制非同期」フラグは、要素がその意志スクリプトのリストの最後に を追加する必要があります設定されていません。できるだけ早く の順番で、 にあるスクリプト要素のドキュメントに関連付けられたスクリプトアルゴリズムの準備が開始されるまで実行します。要素は今のスクリプト のリストの最初の要素ではない場合

:タスクキュー上の

タスクネットワーキング・タスクソースの場所、それは一度、次の手順を実行する必要がありますフェッチアルゴリズムが完了しました 可能な限り早く実行され、 、の順に実行され、その要素は準備完了としてマークされますが、これらのステップは、 がまだ実行されていません。

実行:最初のスクリプト に対応するスクリプトブロックを実行します。このスクリプトのリストは、 が実行されるとすぐに実行されます。

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

の順番で実行されるこのスクリプトのリストが空ではなく、最初のエントリがすでに としてマークされている場合は、実行とラベル付けされたステップに戻ります。要素は、src属性を持っている場合

要素は が起動スクリプトアルゴリズムを準備する時に、すぐにscript要素のドキュメント の可能な限り実行されるスクリプトの セットに追加する必要があります。

タスクキュー上のネットワーキング・タスクソースの場所を一度フェッチアルゴリズムが完了した というタスクは、スクリプトブロックと を実行する必要があり、その後できるだけ早く として実行されるスクリプトのセットから要素を削除します。

他のスクリプトがすでに実行中であっても、ユーザエージェントはすぐにスクリプトブロック を実行する必要があります。

+0

答えに感謝しますが、問題はスクリプト*が*ページに動的に追加されていることを意味します。これは[asyncとみなされます](http://stackoverflow.com/questions/3408805/is-the-async- script-is-dynamic-added-to-the-attribute-property-useful-if-a-the-script-is-the-the-the-the-the-the-the-the-the-the-the-the-the-the-それとも、でのみ動作しますか?私の経験では、彼らは文書順に実行されていますか? – Bergi

+0

@Bergi - 動的に追加された場合は、非同期であり、実行順序は制御するコードを記述しない限り不確定です。 – jfriend00

+0

ちょうど、[Kolink states](http://stackoverflow.com/a/8996905/1048572)反対... – Bergi

11

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

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

注文は "追加" されています。この事実をテストする

- > "final"

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

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

+0

その動作を確認することができます。しかし、私たちのフィードバックページにはヒントがあり、test.phpがキャッシュされているときにしか動かないかもしれません。これに関するスペック/リファレンスリンクをご存知ですか? – Bergi

+4

link.jsがブロックされていません。あなたのPHPに似たスクリプトを使って、長いダウンロード時間をシミュレートしてください。 – 1983

+10

この回答は間違っています。 「動的に追加されたスクリプトがドキュメントに追加されるとすぐに実行される」とは必ずしも言えません。場合によってはこれは当てはまります(たとえば、古いバージョンのFirefoxの場合)。通常はそうではありません。実行順序は、jfriend00の答えに記載されているとおり、確定的なものではありません。 –