web-dev-qa-db-ja.com

JavaScript document.writeインラインスクリプト実行順序

次のスクリプトがあります。最初と3番目のdocument.writelineは静的で、2番目が生成されますです。

<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script language='javascript' type='text/javascript'>alert('during');<\/sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

FirefoxおよびChromeは before during および after を表示しますが、インターネットExplorerは最初に during を表示し、次に before および after を表示します。

私が遭遇したのは そのことを述べている記事 私はこれに最初に出会ったわけではないが、それで気分が良くなることはほとんどない。

すべてのブラウザで順序を決定的に設定する方法を知っているか、IEをハックして他のすべてのブラウザと同じように動作させることができますか?

警告:コードスニペットは非常に単純な再現です。サーバー上で生成され、変更されるのは2番目のスクリプトだけです。これは長いスクリプトであり、その前後に2つのスクリプトがある理由は、ブラウザーがそれらをキャッシュし、コードの動的な部分をできるだけ小さくするためです。また、生成されたコードが異なる同じページに何度も表示される場合があります。

36

私は自分の好みにさらに答えを見つけました:

<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script defer language='javascript' type='text/javascript'>alert('during');<\/sc" + "ript>");
document.write("<script defer language='javascript' type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

これにより、ページの読み込みが完了するまで、の両方の読み込みが延期されます。

これは私が得ることができるのと同じくらい良いと思います。うまくいけば、誰かがより良い答えをすることができるでしょう。

5

いいえ、これはInternet Explorerの動作です。

スクリプトを動的に添付する場合、IE、Firefox、およびChromeはすべて、非同期の方法でスクリプトをダウンロードします。

FirefoxとChromeはすべての非同期リクエストが返されるまで待機し、DOMにアタッチされている順序でスクリプトを実行しますが、IEはワイヤを介して返される順序でスクリプト。

アラートは、外部のJavaScriptファイルよりも「取得」にかかる時間が短いため、表示されている動作を説明している可能性があります。

Kristoffer Henrikssonの 非同期スクリプトの読み込みに関する投稿 から:

このシナリオでは、IEとFirefoxは両方のスクリプトをダウンロードしますが、Internet Explorerはダウンロードを完了した順に実行しますが、Firefoxは非同期にダウンロードしますが、接続された順に実行しますDOM。

Internet Explorerでは、ネットワークトラフィック、キャッシュなどによって実行順序が異なるため、スクリプトが相互に依存関係にないことを意味します。

Javascriptローダーの使用を検討してください。これにより、スクリプトの依存関係と実行順序を指定できるようになります。また、速度を上げるために非同期でスクリプトをロードするだけでなく、ブラウザーの違いの一部を平滑化します。

これはそのうちのいくつかの非常に良い概要です: 必須のJavaScript:上位5つのスクリプトローダー

RequireJSとLabJSの両方を使用しました。私の意見では、LabJSの意見は少し劣っています。

24

さて...中に...

// During.js
during[fish]();

後...

// After.js
alert("After");
fish++

HTML

<!-- some html -->
<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript'>during[" + fish + "] = function(){alert('During!' + fish);}</sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='during.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'></sc" + "ript>");
</script>
<!-- some other html -->
<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript' src='before.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript'>during[" + fish + "] = function(){alert('During!' + fish);}</sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='during.js'></sc" + "ript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'></sc" + "ript>");
</script>

しかし、私はこれが臭い始めている方法について同意したいです。特に、動的に作成されたjsファイルに「実行中」をコード生成して挿入できないのはなぜですか?

動的に生成されるスクリプトはinsidesecond document.writeの関数に行くことに注意してください。
FF2、IE7でテスト済み

1
Dustman

このプレゼンテーション のスライド25/26では、スクリプトを挿入するさまざまな方法の特性について説明しています。 IEがこれらのスクリプトを順番に実行する唯一のブラウザです。他のすべてのブラウザは、ロードが完了する順に実行します。偶数IE srcの代わりに1つ以上のインラインjsがある場合、それらを順番に実行しません。

推奨される方法の1つは、新しいDOM要素を挿入することです。

var se1 = document.createElement('script');
se1.src = 'a.js';

var se2 = document.createElement('script');
se2.src = 'b.js';

var se3 = document.createElement('script');
se3.src = 'c.js';

var head = document.getElementsByTagName('head')[0]
head.appendChild(se1);
head.appendChild(se2);
head.appendChild(se3);

2番目のスクリプトセクションを生成するには、スクリプトを使用してそのコンテンツを生成し、パラメーターを渡すことができます。

se2.src = 'generateScript.php?params=' + someParam;

編集:私がサイトに掲載した記事に書かれていることにもかかわらず、私のテストでは、ほとんどのブラウザがdocument.writeスクリプトにそれぞれsrcがあれば順番に実行することを示唆しているので、上記の方法が好ましいと思いますが、これも行うことができます:

<script language="javascript" type="text/javascript">
document.write("<script type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

もう一度編集(自分や他の人へのコメントへの応答):すでにページでスクリプトを生成しています。実行していることはすべて、同じコードブロックを生成する別のサーバー側スクリプトに移動できます。ページにパラメーターが必要な場合は、クエリ文字列でスクリプトにパラメーターを渡します。

また、提案されているように、インラインスクリプトを複数回生成している場合も、この同じ方法を使用できます。

<script language="javascript" type="text/javascript">
document.write("<script type='text/javascript' src='before.js'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params1 + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params2 + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='during.php?params=" + params3 + "'><\/sc" + "ript>");
document.write("<script type='text/javascript' src='after.js'><\/sc" + "ript>");
</script>

ただし、これは間違った方法でアプローチしているように見え始めています。コードの大きなブロックを複数回生成している場合は、おそらく単一のjs関数に置き換えて、代わりに異なるパラメータで呼び出す必要があります...

1
Prestaul

スクリプトで「onload」(または同様の)イベントを定義し、イベント関数に次のイベントを挿入することで、強制的に実行を継続できます。些細なことではありませんが、そこにはたくさんの例があります。ここに一つあります。

http://www.phpied.com/javascript-include-ready-onload/

JQueryやプロトタイプのような人気のあるライブラリがこれに役立つと思います。

1
Victor

提供するコード:

<script language="javascript" type="text/javascript">
document.write("<script language='javascript' type='text/javascript'>function callGeneratedContent() { alert('during'); }<\x2Fscript>");
document.write("<script language='javascript' type='text/javascript' src='before.js'><\x2Fscript>");
document.write("<script language='javascript' type='text/javascript' src='after.js'><\x2Fscript>");
</script>

Before.jsで:

alert("Before");
callGeneratedContent();

After.jsで:

alert("After");

生成された行を最初に置く必要があります。そうしないと、FFは関数定義を見る前にbefore.jsを実行するため文句を言います。

0
PhiLho

どのようにそのことについて:

<script>
document.write("<script src='before.js'><\/script>");
</script>

<script >
document.write("<script>alert('during');<\/script>");
</script>

<script>
document.write("<script src='after.js'><\/script>");
</script>
0
wit