3

ライブラリに依存せずに、条件付きでいくつかの JavaScript ファイル (外部および内部) の実行順序をロードして保持する方法を探しています。基本的に、私がやりたいことは、ブラウザーが localStorage をサポートしている場合にのみそれらをロードすることです。

基本的に私のシェルは次のとおりです。

if (window.localStorage) {
//load up JS only if it's needed
    var body = document.getElementsByTagName('body')[0],
        js1 = document.createElement('script'),
        js2 = document.createElement('script'),
        js3 = document.createElement('script'),
        js4 = document.createElement('script'),
        js5 = document.createElement('script');

    js1.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js';
    js2.src = 'http://www.google.com/jsapi';
    js3.src = 'my_file1.js';
    js4.src = 'my_file2.js';
    js5.src = 'my_file3.js';

    body.appendChild(js1);
    body.appendChild(js2);
    body.appendChild(js3);
    body.appendChild(js4);
    body.appendChild(js5);
} else { 
    //no localStorage support, display messaging
}

createElement/body.appendChild を使用してスクリプト ノードを動的に追加しようとしましたが、うまくいかないようです。

これを達成する簡単な方法はありますか?現在、すべてが機能していますが、IE6 および IE7 の人々は、スクリプトをダウンロードしても実行していません。これを修正したいと考えています。

4

3 に答える 3

6

ノードの追加scriptはうまくいくはずです。これらのスクリプトはそれらを追加するコードに対して非同期的に実行されるため、次のことを順番に実行するために呼び出すコールバックを与える必要があります。例えば:

if (window.localStorage) {
    // Load the local storage stuff; once loaded, it'll call
    // `doTheNextThing`
    var script = document.createElement('script');
    script.type = "text/javascript";
    script.src = /* ... the URL of the script ... */;
    document.body.appendChild(script); // Or append it to `head`, doesn't matter
                                       // and `document.body` is convenient
}
else {
    // Skip loading it
    setTimeout(doTheNextThing, 10);
}

function doTheNextThing() {
    // ...
}

...ロード後のlocalStorageスタッフ呼び出し用にロードしている動的スクリプト。つまり、動的にロードされたスクリプトが存在する場合は呼び出しますが、存在しない場合は上記のコードが呼び出します。上記のコードからの呼び出しを意図的に ( 経由で )非同期にしたことに注意してください。どのように呼び出されるかに関係なく、常に非同期にすることで、バグを見逃す可能性が低くなります (たとえば、同期的に呼び出されることに依存するものを追加してから、テストを忘れるなど)。 IE のマイナー チェンジ)。doTheNextThinglocalStoragedoTheNextThingsetTimeout

更新:上記は、ロードしているスクリプトを制御していることを前提としていますが、そうでないことを明確にしました。その場合、スクリプトを 1 つずつロードし、それらが提供する機能 (通常は のwindowようなオブジェクトのプロパティwindow.jQuery) をポーリングする必要があります。次のようなものです (テストされていません)。

// Load the script designated by `src`, poll for the appearance
// of the symbol `name` on the `window` object. When it shows
// up, call `callback`. Timeout if the timeout is reached.
function loadAndWait(src, name, timeout, callback) {
    var stop, script;

    // Do nothing if the symbol is already defined
    if (window[name]) {
        setTimeout(function() {
            callback("preexisting");
        }, 10);
    }
    else {
        // Load the script
        script = document.createElement('script');
        script.type = "text/javascript";
        script.src = src;
        document.body.appendChild(script);

        // Remember when we should stop
        stop = new Date().getTime() + timeout;

        // Start polling, long-ish initial interval
        setTimeout(poll, 150);
    }

    function poll() {
         if (window[name]) {
             // Got it
             callback("loaded");
         }
         else if (new Date().getTime() > stop) {
             // Time out
             callback("timeout");
         }
         else {
             // Keep waiting, shorter interval if desired
             setTimeout(poll, 75);
         }
    }
}

...これは、jQuery の読み込みに次のように使用します。

loadAndWait(
    "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
    "jQuery",
    10000, // ten seconds or whatever
    function(result) {
        // ...do the next one if result !== "timeout"
    }
 );

loadAndWait以前の呼び出しのコールバックのそれぞれに呼び出しをネストするか、配列とカウンターを使用できます。

loadThese(
    [
        {   src:    "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
            symbol: "jQuery"
        },
        {
            src:     "http://the-next-one",
            symbol:  "nextSymbol"
        }
    ],
    doTheNextThing
);

function loadThese(scripts, callback) {
    var index = 0;
    run("okay");

    function run(result) {
        var entry;

        if (result === "timeout") {
            callback(result);
        }
        else if (index < scripts.length) {
            entry = scripts[index++];
            loadAndWait(entry.src, entry.symbol, 10000, run);
        }
        else {
            callback("loaded");
        }
    }
}

そこで、各スクリプトを順番にロードするためにloadThese使用するループを設定します。run

上記のすべては完全にすぐに使えるものであり、おそらく締めて防弾することができますが、アイデアはわかります.

トピック外ですが、私の質問は次のとおりです。実際にコードが多すぎて、それを使用してロードできないブラウザにとって問題になるのでしょうか? ファイルが非常に大きくならない限り、高度なブラウザーを使用しているユーザーの場合、実際にはサイトの速度が低下しますが、他のブラウザーでは何も得られません. 特定のサイズを下回ると、サーバーに接続してスクリプトを取得するオーバーヘッドは、スクリプトの転送と同じくらい大きな要因になります。余分なものは 50k のコードですか? それが本当に必要かどうかをテストするために、いくつかのベンチマークを行います...おそらくそうです(おそらくすでに持っているでしょう!)が、言及する価値があります...

トピック外の更新localStorage:更新された質問では、サポートされている場合にダウンロードする 5 つの個別のスクリプトをリストします。さまざまな CDN から 5 つすべてを取得していると仮定しても、(通常の方法で行うか、上記の方法で行うかにかかわらず) 多数の個別のスクリプト リクエストがあり、それぞれを一度に 1 つずつ処理する必要あります。これは、発生するのを待っているページ読み込みのパフォーマンスの問題です。(おそらく) CDN と既存のキャッシュの利点を失うにもかかわらず、これらのスクリプトをすべて取得して結合し、結合したバージョンを 1 つのファイルでホストすることを検討するかもしれません。YUI パフォーマンスの「ルール」の「HTTP リクエストの最小化」を参照してください(私は「ガイドライン」という用語を好みますが、何でも構いません)。また、動的ロードを簡素化します。

于 2010-10-19T23:01:46.867 に答える
2

onload とクロージャ関数を組み合わせて使用​​できます。次のようなもの:

function loadScripts(index) {
    return function () {
        var e = document.createElement('script');
        e.src = scripts[index];
        document.body.appendChild(e);

        if (index + 1 < scripts.length) {
            e.onload = loadScripts(index + 1)
        }
    };
}

そして、次のように呼び出します。

loadScripts(0)();
于 2011-04-30T05:35:53.103 に答える
0

このコードを使うようになりました。メイン関数 (addEvent と load_javascript) は両方とも Web 上にあります。
ただし、ダウンロード サイズを小さくしようとしているわけではありません。これが、リソースをロードできる唯一の方法です。したがって、Šime Vidasによって提案されたアイデアは、あなたにとって理にかなっているかもしれません。

addEvent = function(elm, evType, fn, useCapture) {
    //Credit: Function written by Scott Andrews
    //(slightly modified)
    var ret = 0;

    if (elm.addEventListener) {
        ret = elm.addEventListener(evType, fn, useCapture);
    } else if (elm.attachEvent) {
        ret = elm.attachEvent('on' + evType, fn);
    } else {
        elm['on' + evType] = fn;
    }

    return ret;
};


    var left_to_load = 0;
    function init() {
        --left_to_load;
        if (left_to_load > 0) {
            return;
        }

        // all scripts are loaded now
        // proceed with your logic
    }

    // load js file and call function when done
    function load_javascript(src, callback) {
        var a = document.createElement('script');
        a.type = 'text/javascript';
        a.src = src;
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(a, s);

        ++left_to_load;
        addEvent(a, 'load', callback, false);
    }



load_javascript('url1', init);
load_javascript('url2', init);
...
于 2010-10-19T23:03:42.820 に答える