JavaScript の動的ロード


JavaScript にはコードを動的に読み込む仕組みがほとんどありません。少なくとも、ECMAScript 単独では無理のようです。

[pukiwiki]
で、先人たちがなにをやっているのか調べてみたたところ、昨日 Delicious に登録したように[[JavaScript を動的に読み込むための4つの方法:http://ntt.cc/2008/02/10/4-ways-to-dynamically-load-external-javascriptwith-source.html%5D%5Dが見つかりました。4つあるとは言っても、基本的には2つです。

最初は、HTML の DOM をいじって script タグを挿入する方法。このやり方に3種類あるということです。説明を見たところ、この方法は非同期的だということでした。つまり、ロードをすることはできるのだけれども、ロードを待ってコードを実行する仕組みがないとのことです。

もうひとつの方法は、XMLHTTP を用いてコードを取得し、そのコードをHTMLに埋め込む方法です。((どうして eval を使わないで、HTML に script タグを埋め込む???ロードって実質的に eval なのに、eval を避けるために DOM をいじるのはかえって遠回りじゃないの?))この方法の利点は同期的なのだそうです。なぜかは理解していません。

最初の方法に近い方法は[[あまちゃんさんも提案:http://d.hatena.ne.jp/amachang/20071116/1195202294%5D%5Dしています。彼の方法は、script タグを挿入後にタイマ割り込みを使って、コードがロードされるのをビジーウェイトする方法です。かなり凝った方法のように思えます。

このあまちゃんさんの方法にヒントを得て、もう少し分りやすい方法を探ってみました。実装方針は、あまちゃんさんと同様に script タグを挿入する方法です。ただ、動的ロードの仕組みに簡単なプロトコルを用意して、

– 動的ロードを始めた側は継続を保存し
– 動的ロードされた側は、ロード完了時に保存された継続を呼び出す

という方法をとりました。特殊なプロトコルを使っているのでずるいかもしれませんけれども、プロトコル自体は簡単です。以下がサンプルです。

**動的なコードの読み込み

ken.require(
“a”, “module_a.js”,
function (name) { alert(name + ” is loaded”); });

”ken.require(id, url, cont)” はモジュール名 (id)、ファイルのURL (url)、モジュールが読み込まれたあとで実行される継続 (cont) を引数として取ります。

モジュール名は、読み込まれたモジュールの管理に使っています。一応、同じモジュールが複数回、読み込まれることや、url で指定されたファイルが HTML のなかで静的に読み込まれる場合も想定しています。

継続は、指定されたファイルが読み込まれた段階でそのファイルのなかから呼び出すものとします。

** 動的に読み込まれるコード

ken.require.onload(“a”, function (cont) { cont(“Module A”); });

動的に読み込まれるコードの最後には ”ken.require.onload(id, initializer)” を実行することとします。

前述の require を使うと、その都度、継続が保存されていくのですが、それを順に実行するときに用いるのが initializer です。上の例は、継続への引数にモジュールの名称を渡しています。

**動作確認ページ

動作を確認したい人は[[こちら:http://kwakita.sakura.ne.jp/work/js/require/%5D%5Dです。JavaScript 初心者のぼくが作って、おまけにほとんどデバッグしてないから、使うときは要注意です。

[/pukiwiki]