jsを用いて動的にscriptを読み込む際の注意点
javascriptを用いて動的にscriptを読み込む際、ハマってしまったのでメモしておきます。
やりたいこと
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="script_with_jquery.js"></script>
</head>
上記のように、head内でscriptを読み込むサイトがあるとします。
ページによっては使用しないスクリプトがあるので、これらのスクリプトをjavascriptで動的に読み込むように改良したいというわけ。
ポイントは2つのjsファイルに依存関係があること。
今回は、script_with_jquery.jsというファイルはjquery.min.jsに依存している。
大元のコード
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="script_with_jquery.js"></script>
</head>
これは正しく動作します。
しっかりjqueryを読み込んだ後に、script_with_jquery.jsを読み込んでいるので大丈夫です。
動きそうで動かないコード
<head>
<script>
var head = document.getElementsByTagName('head')[0];
var script1 = document.createElement("script");
script1.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js';
head.appendChild( script1 );
var script2 = document.createElement("script");
script2.src = 'script_with_jquery.js';
head.appendChild( script2 );
</script>
</head>
私は、上記のようなコードを書いて、期待通りに動かなくて頭を悩ませました。
一見動きそうに見えませんか?(運が良ければ動きます。)
javascriptにて、scriptを動的に生成しています。
依存関係を守るため、先にjqueryの方をappendChildして、その後、script_with_jquery.jsをappendChildしています。
なぜ動かないかというと、、、
javascriptを用いて動的に読み込む際に非同期通信が発生する
はい。というわけです。落ち着いて考えてみれば当然のことなのですが。。。
つまり、javascriptを用いてscriptをappendChildした場合、そのscriptが完全に読み込まれる前に次の行の処理に移行してしまう。
ということは、順番通りにappendChildしても、その順番通りにscriptが読み込まれるとは限らないということです。(運よくjavascriptのダウンロードと展開が次の行のjavascriptよりも先に完了すれば、正常に動作してしまいます。)
ではどうするか?(動くコード)
そこで、以下のように改良します。
<head>
<script>
var head = document.getElementsByTagName('head')[0];
var script1 = 'https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js';
var script2 = 'script_with_jquery.js';
var script_src_list = [ script1, script2 ];
var script_idx = 0;
function execute_scripts() {
var script = document.createElement("script");
script.src = script_src_list[ script_idx ];
head.appendChild( script );
if ( ++script_idx < script_src_list.length ) {
script.onload = execute_scripts;
}
}
execute_scripts();
</script>
</head>
javascriptにて生成したscriptに、onload関数を指定します。
onload関数で、1つ目のscriptがロードされたら、2つ目のscriptを読み込みを実行する。という動作を実現しています。
これで、無事依存関係を崩さずにscriptを動的に読み込むことが可能となりました。
これで頭を悩ませてる人、私だけでしょうか・・・?
以上、jsを用いて動的にscriptを読み込む際の注意点についてでした。