【问题标题】:How can I force an array of scripts to load in sequential order?如何强制按顺序加载一组脚本?
【发布时间】:2014-08-06 21:37:15
【问题描述】:

我正在构建一个单页 Web 应用程序,每个“小部件”可能需要一个或多个 JavaScript 或 jQuery 库。其中一些脚本可能依赖于其他脚本,但如果我只是创建一系列$.getScript 调用,它们可能会乱序加载。如何强制按顺序加载脚本,即进程在请求脚本 2 之前等待脚本 1 下载等?

【问题讨论】:

  • 您正在描述 javascript 依赖管理库(如 require.js)的功能。

标签: javascript jquery ajax promise getscript


【解决方案1】:

您可以对脚本名称数组使用reduce 方法。

这里是这种方法的一个例子:

// Load Script and return promise
function loadScript(script) {
  return $.getScript(script);
}
/**
 * Load list of scripts
 */
function loadScripts(scripts) {
  // Reduce, causes sequenctial order of execution
  return scripts.reduce(function(cur, next){
    // When promise is complete, return next promise (loadScript)
    return cur.then(function(){
      console.log(next);
      // Load the next script and return promise
      return loadScript(next);
    });
  }, $().promise() /* First promise is an empty promise */); 
}

(JSBin)

简而言之:

function loadScripts(scripts) {
    return scripts.reduce(function(cur, next){ 
        return cur.then($.getScript.bind($, next));
    }, $.when());
}
loadScripts(["./1.js","./2.js","./3.js").then(function(){ // example usage
    // all done here
});

【讨论】:

  • 虽然您的场景听起来很疯狂,但我真的不建议动态加载脚本并强制执行命令。这听起来像是一场维护和调试的噩梦。
  • 在所有的答案中,这绝对是最干净的。
【解决方案2】:

此函数接受脚本的 URI 数组并按顺序加载它们,返回一个 jQuery 承诺,该承诺将在集合中的最后一个脚本加载时解析。

$.load_scripts_sequentially = function (scripts) {
    var deferred = new $.Deferred();
    var load_script = function (index) {
        var scripts = this;
        if (index > scripts.length - 1) {
            deferred.resolve();
            return;
        }
        $.getScript(scripts[index])
            .done($.proxy(function () {
                load_script.call(this.scripts, this.index + 1);
            }, {scripts: scripts, index: index}))
            .fail($.proxy(function () {
                console && console.error('Failed to load script: ' + this.scripts[this.index], arguments);
                deferred.reject();
            }, {scripts: scripts, index: index}));
    };
    load_script.call(scripts, 0);
    return deferred.promise();
};

示例用法:

$.load_scripts_sequentially(['1.js', '2.js', '3.js']).done(function () {
    console && console.info('All scripts done loading!');
});

【讨论】:

  • 我不确定你为什么在这里使用延迟,因为你自己已经有效地实现了异步信号量。 $.getScript 已经返回了一个链式承诺。
【解决方案3】:

您可以使用异步库来确保按顺序加载所有库。 https://github.com/caolan/async#eachSeries

或者,正如另一位用户指出的那样,您可以使用 require.js

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    相关资源
    最近更新 更多