有条件地加载javascript(外部和内部)并保持执行顺序 [英] conditionally load javascript (external and internal) and keep execution order

查看:88
本文介绍了有条件地加载javascript(外部和内部)并保持执行顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种有条件地加载并保持某些javascript文件(外部和内部)的执行顺序而没有任何库依赖性的方法.基本上,我只想在浏览器支持localStorage时加载它们.

I'm looking for a way to conditionally load and keep the execution order of some javascript files (external and internal) without any library dependency. Basically, what I want to do is load them up only if the browser supports 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动态添加脚本节点,但这些似乎无效.

I've tried dynamically adding script nodes via createElement/body.appendChild but those don't seem to work.

有没有简单的方法可以做到这一点?现在一切正常,但是IE6和IE7的人下载了他们甚至没有执行的脚本,这是我要修复的问题.

Is there an easy way to achieve this? Right now everything works, but IE6 and IE7 folks download script they aren't even executing, which is what I want to fix.

推荐答案

添加script节点应该可以正常工作.因为这些脚本将与添加它们的代码异步执行,所以您需要给它们一个回调以调用以按顺序执行下一步.例如:

Adding script nodes should work just fine. Because those scripts will execute asynchronously to the code adding them, you'll need to give them a callback to call to do the next thing in order. E.g.:

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内容加载的动态脚本在doTheNextThing加载后调用doTheNextThing因此,在有localStorage的情况下,动态加载的脚本将调用doTheNextThing,但在没有doTheNextThing的情况下,上面的代码会实现.请注意,我故意从上面的代码进行了异步调用(通过setTimeout进行调用):无论调用方式如何,始终使其始终异步 减少了丢失错误的几率(例如,添加了依赖会被同步调用,然后忘记测试IE上的细微变化.

...where the dynamic script you're loading for the localStorage stuff call doTheNextThing after it loads — so in the case where there's localStorage, the dynamically-loaded script calls doTheNextThing but in the case where there isn't, the code above does. Note that I made the call from the code above asynchronous (via setTimeout) on purpose: Making it always asynchronous regardless of how it gets called reduces your odds of missing bugs (e.g., adding something that relies on it being called synchronously and then forgetting to test that minor change on IE).

更新:以上假设您可以控制要加载的脚本,但已明确说明自己没有.在这种情况下,您需要做的是一次加载一个脚本并轮询它们提供的功能(通常是window对象的属性,例如window.jQuery),如下所示(未经测试):

Update: The above assumes you're in control of the script you're loading, but you've clarified that you're not. In that case, what you need to do is load the scripts one at a time and poll for the feature that they provide (usually a property on the window object, like window.jQuery), something like this (untested):

// 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:

...which you'd use like this for the jQuery load:

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的调用,也可以使用数组和计数器:

You can either nest calls to loadAndWait in each of the previous calls' callbacks, or use an array and counter:

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设置循环以依次加载每个脚本.

There, loadThese sets up a loop using run to load each script in turn.

以上所有内容都是现成的,可以收紧且防弹,但您明白了.

All of the above is completely off-the-cuff and can probably be tightened and bullet-proofed, but you get the idea.

离题,但是我的问题是:是否真的有太多代码,以致于浏览器无法使用它来加载它?除非文件变大 ,否则实际上对于使用高级浏览器的用户,您的网站速度会降低,而在其他浏览器上却不会获得任何好处.在一定大小以下,连接到服务器以检索脚本的开销与传输脚本一样大.是多余的代码50k吗?我会做一些基准测试来测试它是否真的有必要……也许是(也许您已经拥有了!),但是值得一提……

Off-topic, but my question is: Is there really so much code that it's a problem for the browsers that can't use it to load it? Barring the files getting a lot bigger, you'll actually slow down your site for users with advanced browsers without gaining much of anything on the others. Below a certain size, the overhead of connecting to the server to retrieve the script is as big a factor as transferring it. Is the extra stuff 50k of code? I'd do some benchmarking to test whether it's really necessary... Perhaps it is (perhaps you already have!), but it's worth just mentioning...

主题外更新:在更新的问题中,如果支持localStorage,则列出要下载的五个单独的脚本.即使假设您从各种CDN中获得全部五个,这也是很多单独的脚本请求(无论是按常规方式还是如上所述),每个必须一次处理.那是一个页面加载性能问题,正在等待发生.尽管(可能)失去了CDN和现有缓存的好处,但您可能会希望抓住所有这些脚本,将它们组合在一起,然后将组合后的版本托管在一个文件中.请参见 YUI性能规则" 中的最小化HTTP请求"(我更喜欢术语准则",但无论如何).它还可以简化您的动态加载.

Off-topic update: In your updated question, you list five separate scripts you'd be downloading if localStorage is supported. Even assuming you're getting all five from various CDNs, that's a lot of individual script requests (whether done in the usual way or as above), each of which has to be processed one at a time. That's a page load performance issue waiting to happen. Despite (possibly) losing the benefits of CDNs and existing caching, you might look at grabbing all of those scripts, combining them, and hosting your combined version in a single file. See "Minimize HTTP Requests" in the YUI performance "rules" (I prefer the term "guideline", but whatever). It would also simplify your dynamic loading.

这篇关于有条件地加载javascript(外部和内部)并保持执行顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆