Sjaxを使わないJavaScript Loader

最新版はこちら → JavaScriptで外部ライブラリを読み込むためのスクリプトをCodeRepos.orgに上げた。 - ヒルズで働く@robarioの技ログ



id:amachangさんの社外勉強会の資料 (JavaScript 依存解決手法) - IT戦記を読ませていただきました。

最近作ってみた自作のLoaderについて書きます。

  • Sjaxだと外部ドメインスクリプトが読めない。→Sjaxは使わない。
  • ページの読み込みを早くするために、全てをwindow.onload以降に動かしたい。→document.writeは使わない。

ということで、script要素をDOMで突っ込むことが必要です。しかし、それでは読み込みの完了を待たずに処理が進んでしまうので、今までは「setTimeoutで1000ms後に処理」とか書いていました。外部スクリプトが置いてあるサーバーが落ちていると、読み込めていないのに処理が走ってしまったり。何か嫌。
そこで「指定したプロパティがwindowオブジェクトに追加されたか」を監視するという制御にしてみました。少々姑息な感じは否めませんが^^;

function include(libs, onload) {
    for (var prop in libs) {
        if (!window[prop]) {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.charset = 'UTF-8';
            script.src = libs[prop];
            document.documentElement.appendChild(script);
        }
    }
    if (!onload) {
        return;
    }
    setTimeout(function() {
        for (var prop in libs) {
            if (!window[prop]) {
                setTimeout(arguments.callee, 100);
                return;
            }
        }
        onload();
    }, 0);
};

SYNOPSISはこんな感じで。

include({
    Prototype: 'http://localhost:3000/lib/prototype.js?' + (new Date()).getTime(),
    TrimPath: 'http://localhost:3000/lib/trimpath/template.js?' + (new Date()).getTime()
}, function() {
    // 読み込み完了
});

第1引数には「windowオブジェクトに追加されるプロパティ名」と「スクリプトファイル名」の連想配列を渡します。第2引数は全ての読み込みが完了してから実行する関数で、省略可能です。

多段にもできます。「読み込んだら即座に処理を行うmyscript.js(要prototype.js)」がある場合、予めprototype.jsを読み込んでおくには

include({
    Prototype: 'http://localhost:3000/prototype.js',
}, function() {
    include({
        myscript_js_dummy: 'file:///C:/js/myscript.js',
    });
});

と書けます。myscript.jsは読み込み完了を待つ必要がないので、第2引数は指定していません。指定するプロパティ名も適当です。script要素なのでfileスキームでも大丈夫です。include内をごにょごにょして依存関係を各ファイルに書けるようにしてみる予定。どうでしょう?複雑過ぎてダメかな。

あとはJSONが出始めた頃にあったような、こんなdata.jsがあるとき、

var data = {"key": "value"};

こんな風にできたりもします。

include({data: "data.js"}, function(){
    console.info(data);
});