web-dev-qa-db-ja.com

JavaScriptコードを同期してロードして実行する

同期XMLHttpRequestのような同期方法でjavascriptファイルをロードして実行する方法はありますか?

私は現在、同期XMLHttpRequestを使用しており、これを評価していますが、そのコードのデバッグは非常に困難です...

ご協力いただきありがとうございます!

更新

私は今これを試しました:

test.html

<html>
    <head>
        <script type="text/javascript">
            var s = document.createElement("script");
            s.setAttribute("src","script.js");
            document.head.appendChild(s);
            console.log("done");
        </script>
    </head>
    <body>
    </body>
</html>

script.js

console.log("Hi");

出力:こんにちは

そのため、同期的に実行されませんでした。 「こんにちは」を最初に表示するアイデアはありますか?

更新2その他の例

test.html(スクリプトタグ内のコード)

var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
SayHi();

script.js

function SayHi(){
    console.log("hi");
}

出力:キャッチされていないReferenceError:SayHiは定義されていません

39
Van Coding

これを使用する場合:

function loadScriptSync (src) {
    var s = document.createElement('script');
    s.src = src;
    s.type = "text/javascript";
    s.async = false;                                 // <-- this is important
    document.getElementsByTagName('head')[0].appendChild(s);
}

必要なことを実行できます(ただし、追加のスクリプトファイルに分割されます)

test.html(スクリプトタグ内のコード):

loadScriptSync("script.js");
loadScriptSync("sayhi.js"); // you have to put the invocation into another script file

script.js

function SayHi() {
     console.log("hi");
}

sayhi.js

SayHi();
20
heinob

DOMの準備が整った後に読み込まれるすべてのスクリプトは、非同期で読み込まれます。ブラウザがそれらを同期的にロードする唯一の理由は、何かを出力できる関数writeです。したがって、スクリプト要素のonloadコールバックを使用して、目的を達成できます。

var s = document.createElement("script");
s.setAttribute("src","script.js");
s.onload = function(){
    console.log('Done');
}
document.head.appendChild(s);

別の方法は、XHRを介してjsファイルをロードし、script要素内にコードを設定することです。

window.onload = function(){
    var req = new XMLHttpRequest();
    req.open('GET', "test.js", false);
    req.onreadystatechange = function(){
        if (req.readyState == 4) {
            var s = document.createElement("script");
            s.appendChild(document.createTextNode(req.responseText));
            document.head.appendChild(s);
        }
    };
    req.send(null);
}
18
bjornd

同様の質問から( https://stackoverflow.com/a/3292763/235179 ):

_<script type="text/javascript">
  document.write('<script type="text/javascript" src="other.js"><\/script>');
</script>

<script type="text/javascript">
  functionFromOther();
</script>
_

_document.write_ 'dスクリプトから呼び出されるコードは、独自の_<script>_にあるか、window.onload()イベントにある必要があります。

12
Josh Johnson

スクリプトは同期的に実行されます

あなたのコードをまとめると:

1. create script element
2. set its attribute src
3. set its attribute deferred
4. display done...

この最初の部分は実行を停止し、次のスクリプトに引き渡します

5. script executes and displays Hi

すべてが非常に同期しています... Javascriptでは、最後の行まで実行されるか、内部システム(XHRやタイマーなど)に実行を渡すまで、一部のコードが完全に実行されます。

後で実行するためにいくつかのパーツを準備したいときは、setTimeoutで準備します。タイムアウトが他のコードよりも短い場合でも、実行にかかる時間です。コードの実行が完了した後。例:

// some code
setTimeout(function(){ alert("I'm second alert"); }, 1);
longExecutionTask();
alert("I'm the first alert");

上記のコードでは、setTimeoutが1ミリ秒後に実行するように設定されている場合でも、alertボックスの表示で終了する実行終了後のコードまでは開始されません。同じことがあなたの場合にも起こります。コードの最初のバッチは、他の何かを開始する前に実行を終了する必要があります。

例外が発生する理由(例2)

私が答えを書いた後、さらにコードを追加したので、ここで詳細を説明します。

スクリプトタグを追加しても、すぐには実行されません。 HTMLパーサーが追加したSCRIPT要素に到達すると、スクリプトの読み込みと実行が発生します。その時点でそれをロードし、そのコンテンツを評価/実行します。

  1. HTMLパーサーがドキュメントの解析を開始します
  2. HEADが解析され、そのSCRIPT子タグが解析および実行されます。この実行により、まだ解析されていないBODYタグにもう1つの要素が追加されます。
  3. パーサーはBODYに進み、そのコンテンツ(新しく追加されたSCRIPTタグ)を解析し、スクリプトをロードしてそのコンテンツを実行します。

SCRIPT要素は、ページが解析され、ブラウザで既にレンダリングされた後に追加された場合にのみすぐに実行されます。あなたの場合、そうではありません。最初のスクリプトはすぐに実行され、解析が行われると動的に追加されたスクリプトが実行されます。

5
Robert Koritnik

それらの間で非同期操作を同期できます。ループを表す再帰関数を作成し、前の終了時に次の操作を呼び出します。次の関数は、同様の手法でスクリプトを順番にインポートします。スクリプトがロードされるのを待機し、エラーがない場合は次へ続行します。エラーが発生した場合、エラーイベントでコールバック関数を呼び出し、エラーがない場合は、すべてのスクリプトがロードされた後、同じコールバック関数をnullで呼び出します。また、s.parentNode.removeChild(s)を使用して自動的にクリーンアップします。

function importScripts(scripts, callback) {
    if (scripts.length === 0) {
        if (callback !== undefined) {
            callback(null);
        }
        return;
    }
    var i = 0, s, r, e, l;
    e = function(event) {
        s.parentNode.removeChild(s);
        if (callback !== undefined) {
            callback(event);
        }
    };
    l = function() {
        s.parentNode.removeChild(s);
        i++;
        if (i < scripts.length) {
            r();
            return;
        }
        if (callback !== undefined) {
            callback(null);
        }
    };
    r = function() {
        s = document.createElement("script");
        s.src = scripts[i];
        s.onerror = e;
        s.onload = l;
        document.head.appendChild(s);
    };
    r();
}
0
User0123456789