【问题标题】:Loading javascript files automatically with sequential callbacks使用顺序回调自动加载 javascript 文件
【发布时间】:2010-11-22 10:14:36
【问题描述】:

我有以下javascript列表,这个列表中的每一项都有一个脚本文件url和一个回调函数,我要做的是遍历这个列表,加载每个脚本,然后执行回调函数,然后不移动到下一个项目,除非当前回调完成执行..


var data = { 
    scripts: [
        {
            file    : 'some-script.js',
            callback: function() {
                // do some code here
            },
        },
        {
            file    : 'another-script.js',
            callback: function() {
                // do some code here
            },
        },
        ...
    ]
};

如果可能,我如何自动执行此操作?

【问题讨论】:

  • 题外话:对象字面量中最后一个属性后面的悬空逗号在某些浏览器中会成为问题,详情:blog.niftysnippets.org/2010/09/literal-improvement.html
  • 我放置这个逗号是为了表示要加载的脚本不止这些脚本,无论如何感谢您的评论,也感谢您的帖子,但我认为放置超时不是一个好主意,因为我打算做一些通用的东西,不管它包含什么回调代码..

标签: javascript jquery iteration


【解决方案1】:

(我假设您正在使用 JSONP 加载外部脚本)您将面临的问题是这些脚本不会同时加载。

下面是一些代码,它们会在相关脚本加载后立即调用您的回调函数。

    function include_js(url, callback) {  // http://www.nczonline.net
        var script = document.createElement("script");
        script.type = "text/javascript";

        if (script.readyState) {  //IE
            script.onreadystatechange = function(){
                if (script.readyState == "loaded" || script.readyState == "complete"){
                    script.onreadystatechange = null;
                    callback();
                }
            };
        } else {  //Others
            script.onload = function(){
                callback();
            };
        }
        script.src = url;
        document.getElementsByTagName("head")[0].appendChild(script);
    }

//Edit

    for (var i = 0; i < data.scripts.length; i++) {
         include_js(data.scripts[i].file, data.scripts[i].callback);
    }

【讨论】:

  • 我在这里理解的是,在你的 for 循环中,在匿名函数完成执行它的代码之前,它不会转到列表中的下一个元素?,对吗?
【解决方案2】:

有可能如果在每个脚本中都有可以测试的符号,或者每个脚本在加载完成后是否可以执行函数调用。

加载脚本很容易,我相信你知道:

var script = document.createElement('script');
script.src = /* ... the source path ... */;
document.body.appendChild(script);

(你会看到有人在 head 后面添加;没关系,body 很容易找到。)

但困难的部分是知道它何时被下载和执行。唯一真正做到这一点的方法是轮询以查看脚本定义的新全局符号是否已定义,或者让脚本在加载完成后主动回叫您(a'la JSONP)。

无论哪种方式,一旦您检测到符号或收到回调,您就可以继续加载下一个脚本。

这是一个基于查找全局符号(window 对象上的属性)的快速粗略草图:

// The scripts to load
var scriptList = { 
    scripts: [
        {
            file    : 'some-script.js',
            callback: function() {
                // do some code here
            },
            symbol  : "someSymbol",
            timeout : 30000 // We know this one is slow, give it 30 seconds
        },
        {
            file    : 'another-script.js',
            callback: function() {
                // do some code here
            },
            symbol  : "anotherSymbol"
        },
        // ...
    ]
};

// Triggering the load
loadScripts(scriptList);

// Library routines to do the load
function loadScripts(list)
{
    var index, timeout;

    // Start with the first one (loadNextScript starts with an increment)
    index = -1;
    loadNextScript();

    // This function loads the next script in the list; if there are no
    // more, it simply returns
    function loadNextScript()
    {
        var script;

        // Are there more?
        ++index;
        if (index < list.length)
        {
            // Yes, append a `script` element
            script = document.createElement('script');
            script.src = list.file;
            document.body.appendChild(script);

            // Determine when to time out
            timeout = new Date() + (list[index].timeout || 20000); // Time out in Xms, default 20 seconds

            // Start polling
            setTimeout(pollForScript, 0); // Async, but almost immediately (4-10ms on most browsers)
        }
    }

    // This function polls to see if the current script has loaded yet by
    // checking for a global symbol it defines.
    function pollForScript()
    {
        var result;

        // Has it been too long?
        if (new Date() > timeout)
        {
            // Yes
            result = "timeout";
        }
        else
        {
            // Has the symbol been defined?
            if (typeof window[list[index].symbol] !== "undefined")
            {
                // Yes
                result = "loaded";
            }
            else
            {
                // Nope, keep waiting
                setTimeout(pollForScript, 250); // Check every quarter-second
            }
        }

        // Did we get a result?
        if (result)
        {
            // Yes, do the callback telling it of the result
            try {
                list[index].callback(result);
            }
            catch (e) {
            }

            // Load the next script
            loadNextScript();
        }
    }
}

【讨论】:

    【解决方案3】:

    让回调调用您的loadTheNextScriptInList 或任何函数。您可以通过向 onLoad 事件添加匿名函数来自动执行此操作。这个匿名函数应该先调用列表中设置的回调,然后再调用你的loadTheNextScriptInList函数。

    【讨论】:

      【解决方案4】:

      这只是我写的很快并没有经过测试的东西,但它应该以递归的方式完成你所追求的。希望这会有所帮助:

      var data = { 
          scripts: [
              {
                  file    : 'some-script.js',
                  callback: function() {
                      // do some code here
                  },
              },
              {
                  file    : 'another-script.js',
                  callback: function() {
                      // do some code here
                  },
              },
              ...
          ]
      };
      
      
      $(document).ready(function() {
      
          if(data.scripts.length > 0) {
              scriptLoader(0);
          }
      
      });
      
      function scriptLoader(i) {
      
      
          var currScript = data.scripts[i];
      
      
          $.getScript(currScript.file, function() {
      
            // execute your callback
            currScript.callback();
      
            // load next script
            if(i < data.scripts.length) {
              scriptLoader(i++);
            }
      
          });
      
      }
      

      哦,顺便说一句,这使用了 JQuery javascript 框架,仅供参考。

      【讨论】:

      • 只是想我会提到这在我尝试动态加载 jquery 时并没有多大用处,它是顺序的依赖文件。不过,否则看起来很简单。 :P
      猜你喜欢
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-06
      • 2010-11-12
      相关资源
      最近更新 更多