2010-04-04 10:24:41

[jQuery] 外部JavaScriptファイル読込みに関する考察

テーマ:JavaScript

前回の「GO2WEB20のTwitterバッチをAmebloにつけてみた。と、IE対策方法 」に端を発してjQueryを使って外部のJavaScriptのソースを読み込む際の様々なやり方の検証をしてみる。



append()を使ってscriptタグを追加する


jQueryのappend()を使ってタグを追加できますのでこれでscriptタグを追加してみます。


<script>
$(document).ready(function(){

    var script_tag     = document.createElement("script");
    script_tag.type    = "text/javascript";
    script_tag.src     = "hoge.js";
    script_tag.charset = "utf-8";

    $("body").append(script_tag);

})
</script>


function foo() {
    alert('hello');
}

foo();


これは、上手く動作します。

ただ、FireBugなんかでHTMLを見てみると、scriptタグが追加(表示)されていません。


- FireBugで見てみても追加したscriptタグは表示されない
A Day In The Boy&#39;s Life-jQuery-append1


これは、jQueryがhtmlに挿入後に即時にscriptタグを削除する仕様のようで、append()以外でもprepend()やbefore()、after()でも同様のようです。


参考: jQuery の挙動を解読する(32):jQuery.clean() メソッド解読──jQuery解読(49) @ anything from here


しかし実際には、append実行時には即時に読み込んだJavaScriptが実行されてます。

ってことは、先にappendしたscript内で定義した関数なんかは呼び出し可能なんでしょうか。

タグ自体がHTML要素内で削除されているので、なんだか呼び出しできない気がします。

ということで、下記のようにJavaScriptを分けて各パターンで実行してみます。


<script type="text/javascript" src="foo.js"></script>
<script>
  foo();
</script>

同じことをするために2つのscriptタグを生成してbodyにappendしてみます。


<script>
$(document).ready(function(){

    var script_tag1     = document.createElement("script");
    script_tag1.type    = "text/javascript";
    script_tag1.src     = "foo.js";
    script_tag1.charset = "utf-8";

    $("body").append(script_tag1);

    var script_tag2     = document.createElement("script");
    script_tag2.type    = "text/javascript";
    script_tag2.charset = "utf-8";
    script_tag2.text    = "foo();";

    $("body").append(script_tag2);

})
</script>


これも動いた!

HTML要素からタグが削除されるていても、先行して読み込んだJavaScript内の関数を呼び出すことは可能なようです。

FireBugのHTML要素では見えないんですが、DOMとしては関数fooが存在していることがわかります。


A Day In The Boy&#39;s Life-jQuery-append2



直接scriptタグを書いてappendToしてみる


書き方としては、さっきの逆になる。


<script>
$(document).ready(function(){

    $("<script type='text/javascript' charset='utf-8' src='foo.js'></scri" + "pt>").appendTo("body");
    $("<script type='text/javascript' charset='utf-8'>foo();</scri" + "pt>").appendTo("body");

})
</script>

これも問題なく動作します。
scriptタグを分割せずにそのまま書いてしまうと「unterminated string litera」と言うことで構文エラーになってしまいます

ですので、scriptの閉じタグを適当なところで分割し、文字列として挿入することで回避するようにします。


参考: Firefox下でのunterminated string literalエラーを回避する @ OKの日記


また、scriptタグがFireBug上で表示されないのはappndの時と同様です。

しかし、先行してappendToしたスクリプト内の関数は、後からapendToしたスクリプト内から実行することは可能です。


こちらの書き方は、単純なJavaScriptなら良いですが、ソースが長くなるとかなり見づらくなってしまいますので適用範囲が限られてくるかもしれません。



$.getScriptを利用して外部JavaScriptをロードする


$.getScriptではHTTPリクエストを通じて外部のJavaScriptファイルを呼び出すことができます。

また、対象のJavaScriptファイルの読込みが成功した場合に実行する関数(コールバック関数)を定義できるため、シンプルで見やすいソースを書くことができます。


- $.getScriptを利用して外部JSファイルをロードし、ロード成功後に関数を実行する

<script>
$(document).ready(function(){
    $.getScript("foo.js", function(){
      foo();
    });
})
</script>


他の書き方より随分とシンプルですね。

foo.jsファイルのロードが正常に完了すると、コールバック関数として第2引数のfunction()内が実行されます。

ですので、ロードするJavaScript内で定義された関数を実行したかったり、その中で定義している変数を書き換えたければコールバック関数内で設定することで、別のJavaScriptをロードする必要がありません。


しかも、$.getScriptを使った場合、JavaScriptの実行を他のスクリプトより遅延して実行させることができます

今までの書き方を複合させて、下記のように書いてみます。

スクリプトの実行順序がわかりやすいように、引数にスクリプト名を渡し、それをalertで表示させるようにしています。

ちなみにfoo1.jsからfoo3.jsまでは中身が全く同じJavaScriptファイルです。


<script>
$(document).ready(function(){

    $.getScript("foo1.js", function(){
      foo('script1');
    });

    $("<script type='text/javascript' src='foo2.js'></scri" + "pt>").appendTo("body");
    $("<script type='text/javascript' charset='utf-8'>foo('script2');</scri" + "pt>").appendTo("body");

    var script_tag1     = document.createElement("script");
    script_tag1.type    = "text/javascript";
    script_tag1.src     = "foo3.js";
    script_tag1.charset = "utf-8";

    $(script_tag1).appendTo("body");

    var script_tag2     = document.createElement("script");
    script_tag2.type    = "text/javascript";
    script_tag2.charset = "utf-8";
    script_tag2.text    = "foo('script3');";

    $("body").append(script_tag2);
})
</script>

これを実行してみると「script2 → script3 → script1」の順でalertが表示されます

スクリプトのロード自体が遅れるのかと思いましたが、そういうわけではなくFireBugで見てみるとロード自体は上から順にされています。


- FireBugで状況をみると$.getScriptでロードしたJSファイルが最初に読み込まれている
A Day In The Boy&#39;s Life-FireBug-コンソール


コールバック関数の実行自体が遅延されるのかとも考えましたが、そういうわけではなく各JSファイルで直接alertを出すようにして読み込んでみても$.getScriptでロードしたスクリプトが一番最後に実行されました。


JavaScriptの動的ロードというのは一般的ですが、その中でも実行順序に変化をもたせたいという場合に、使えるかもしれません。





いいね!した人  |  コメント(2)  |  リブログ(0)

itboyさんの読者になろう

ブログの更新情報が受け取れて、アクセスが簡単になります

コメント

[コメントをする]

2 ■無題

jQueryで外部ファイルから読み込んだプログラム群はすべてちゃんとメモリに残るのでメモリに残っている関数はすべてあとからでも呼び出すことが可能です。なので使う形としては最初に関数や変数を読み込んでおいて、後で使うのがいいと思います。あとからファイルが増えてもいちいちHTMLファイルを書き換えなくてもいいので楽かもしれません

1 ■無題

こんばんは!
調べごとしててたどりつきました~。
もしかしてFANKSさんですかね?!

コメント投稿

AD

Ameba人気のブログ

Amebaトピックス

      ランキング

      • 総合
      • 新登場
      • 急上昇
      • トレンド

      ブログをはじめる

      たくさんの芸能人・有名人が
      書いているAmebaブログを
      無料で簡単にはじめることができます。

      公式トップブロガーへ応募

      多くの方にご紹介したいブログを
      執筆する方を「公式トップブロガー」
      として認定しております。

      芸能人・有名人ブログを開設

      Amebaブログでは、芸能人・有名人ブログを
      ご希望される著名人の方/事務所様を
      随時募集しております。