jQuery:按顺序加载脚本

时间:2012-03-14 22:18:35

标签: jquery ajax asynchronous

我正在尝试使用jQuery动态加载一些脚本:

var scripts = ['script1.js','script2.js','script3.js'];

$.each(scripts , function(i, val) {
     $.getScript(val, function() {
     console.log('loaded '+ val);
});

但有时加载脚本的顺序会发生变化。如何在上一个脚本成功加载后加载每个脚本?

6 个答案:

答案 0 :(得分:17)

您可以使用$.getScript()的回调函数作为递归函数调用,在上一次加载完成后加载每个。

//setup array of scripts and an index to keep track of where we are in the process
var scripts = ['script1.js','script2.js','script3.js'],
    index   = 0;

//setup a function that loads a single script
function load_script() {

    //make sure the current index is still a part of the array
    if (index < scripts.length) {

        //get the script at the current index
        $.getScript(scripts[index], function () {

            //once the script is loaded, increase the index and attempt to load the next script
            console.log('Loaded: ' + scripts[index]);
            index++;
            load_script();
        });
    }
}

代码中发生的事情是同时请求脚本,并且由于它们是异步加载的,因此它们以随机顺序返回并执行。

更新

我没有对此进行过测试,但如果脚本是本地托管的,那么您可以尝试以纯文本格式检索它们,然后将所有代码存储在变量中,直到它们全部被加载,此时您可以评估脚本按顺序:

var scripts   = ['script1.js','script2.js','script3.js'],

    //setup object to store results of AJAX requests
    responses = {};

//create function that evaluates each response in order
function eval_scripts() {
    for (var i = 0, len = scripts.length; i < len; i++) {
        eval(responses[scripts[i]]);
    }
}

$.each(scripts, function (index, value) {
    $.ajax({
        url      : scripts[index],

        //force the dataType to be `text` rather than `script`
        dataType : 'text',
        success  : function (textScript) {

            //add the response to the `responses` object
            responses[value] = textScript;

            //check if the `responses` object has the same length as the `scripts` array,
            //if so then evaluate the scripts
            if (responses.length === scripts.length) { eval_scripts(); }
        },
        error    : function (jqXHR, textStatus, errorThrown) { /*don't forget to handle errors*/ }
    });
});

答案 1 :(得分:10)

您可以利用$.getScript(以及所有其他Ajax方法)返回的jqXhr object实现Promise接口的事实,因此提供.pipe()可用于链接延迟对象的var deferred = new $.Deferred(), pipe = deferred; $.each(scripts , function(i, val) { pipe = pipe.pipe(function() { return $.getScript(val, function() { console.log('loaded '+ val); }); }); }); deferred.resolve();

{{1}}

有关详细信息,请查看deferred objectsdeferred.pipe

总的来说,使用延迟对象可以提供更大的灵活性,并且可以让您更轻松地添加错误处理程序。

答案 2 :(得分:2)

@ Jasper解决方案的增强版本:

  • 使用$.when同步通话。
  • 使用全球评估。

以下是代码:

/**
 * Load scripts in parallel keeping execution order.
 * @param {array} An array of script urls. They will parsed in the order of the array.
 * @returns {$.Deferred}
 */
function getScripts(scripts) {
    var xhrs = scripts.map(function(url) {
        return $.ajax({
            url: url,
            dataType: 'text',
            cache: true
        });
    });

    return $.when.apply($, xhrs).done(function() {
        Array.prototype.forEach.call(arguments, function(res) {
            eval.call(this, res[0]);
        });
    });
}

这个要点:https://gist.github.com/ngryman/7309432

答案 3 :(得分:1)

某些脚本的大小可能会有所不同,因此无法预测。尝试这样的事情。

var scripts = ['script1.js','script2.js','script3.js'], ScriptIndex = 0;
function LoadScript(index){
    if(index >= scripts.length)
        return;

    $.getScript(scripts[index], function(){
        console.log('Loaded script '+ scripts[index]);
        LoadScript(++ScriptIndex);
    }
}

这应该在最后一个脚本完全加载后加载每个脚本。确保通过调用函数LoadScript(0);

启动它

答案 4 :(得分:0)

你可以排序()数组 -

var sorted = scripts.sort();

然后在每个函数中使用sorted。

答案 5 :(得分:0)

@ ngryman的解决方案存在一个小问题;如果要加载的url数组中只有一个url,则.done()函数的参数param将是一个单维数组,而不是2维数组。您需要在循环之前检查参数,因此:

/**
 * Load scripts in parallel keeping execution order.
 * @param {array} An array of script urls. They will parsed in the order of the array.
 * @returns {$.Deferred}
 */
function getScripts(scripts) {
    var xhrs = scripts.map(function(url) {
        return $.ajax({
            url: url,
            dataType: 'text',
            cache: true
        });
    });

    return $.when.apply($, xhrs).done(function() {
        if (arguments.length == 3 && typeof arguments[0] == "string") {
            arguments = [arguments];
        }
        Array.prototype.forEach.call(arguments, function(res) {
            eval.call(this, res[0]);
        });
    });
}

为新答案道歉,没有足够的代表发表评论@ ngryman的答案,但认为这可能会帮助某人!