0

我为javascript制作了一个命名空间框架。我正在加载一些动态添加到 HTML 中的插件(.js 文件)。

我将尝试简化代码。

此函数用于动态加载 JS。加载 .js 文件后调用回调函数。考虑以下代码已经运行。

MYNAMESPACE.plugins = ["plugin1", "plugin2"];
MYNAMESPACE.getJS = {
    get: function (url, callback) {
        var script = document.createElement("script");
        var head = document.getElementsByTagName('head')[0];
        script.type = "text/javascript";
        script.src = url;
        head.insertBefore(script, head.firstChild)
        script.onload = callback;
        script.onreadystate = callback;
        return script;
        }
};

我有一个 init 函数,它加载 MYNAMESPACE.plugins 中包含的插件,如下所示:

MYNAMESPACE.init = function (callback) {
    for (index in MYNAMESPACE.plugins) {
        plugin = MYNAMESPACE.plugins[index];
        MYNAMESPACE.getJS.get(plugin + '.js', function ()
         {
              // This callback is executed when the js file is loaded
         });
    }
    // Here I want to execute callback function, but after all the callbacks in the for loop have been executed.  Something like: if (alljsloaded) callback();
}

在我的 HTML 中,我有以下脚本标签:

<html>
    <head>
    <script type="text/javascript">
        $(document).ready(function () {
            MYNAMESPACE.init(); 

            // The following line is not executed correctlybecause init finished before the scripts are loaded and the functionOnPlugin1 is undefined.
            MYNAMESPACE.functionOnPlugin1();
        });
    </script>
    </head>
    <body>
    </body>
</html>

我想把它改成这样:

<html>
    <head>
    <script type="text/javascript">
        $(document).ready(function () {
            MYNAMESPACE.init(function() { MYNAMESPACE.functionOnPlugin1(); });  
        });
    </script>
    </head>
    <body>
    </body>
</html>

但我不知道如何修改函数 MYNAMESPACE.init() 以便在加载所有插件脚本后执行回调。

有任何想法吗?也许使用闭包。

4

2 回答 2

3
  1. 用于for(;;)循环遍历数组,而不是 for(.. in ..).
  2. 在函数中创建一个计数器,每次加载脚本时递增它。当达到脚本数量时,调用回调函数。

代码:

MYNAMESPACE.init = function (callback) {
    var allPluginsLength = MYNAMESPACE.plugins.length;
    var loadedCount = 0;
    if (allPluginsLength === 0) callback(); // No plugins, invoke callback.
    else for (var index=0; index<allPluginsLength; i++) {
        plugin = MYNAMESPACE.plugins[index];
        MYNAMESPACE.getJS.get(plugin + '.js', function () {
              // This callback is executed when the js file is loaded
              if (++loadedCount == allPluginsLength) {
                  callback();
              }
         });
    }
}

另外,改变你的getJS.get方法。目前,callback总是在状态改变时执行,这是不可取的。为了防止回调被执行两次,可以使用以下方法:

    script.onload = function() {
        callback && callback();
        callback = false;
    };
    // onreadystatechange instead of onreadystate, btw.
    script.onreadystatechange = function() {
        if (this.readyState == 'complete') {
            callback && callback();
            callback = false;
        }
    };
  • callback && callback()使用,以确保存在回调。如果是,则调用它。
  • 调用回调后,它会立即被删除 ( callback = null)。
    这是必要的,因为onloadonreadystatechange事件可以在脚本加载时触发。如果没有我建议的代码,单个脚本将多次调用回调。
于 2012-03-22T17:56:41.507 回答
1

像这样的一些更改应该有效:

MYNAMESPACE.init = function (callback) {
    var remaining = MYNAMESPACE.plugins.length;
    for (index in MYNAMESPACE.plugins) {
        plugin = MYNAMESPACE.plugins[index];
        MYNAMESPACE.getJS.get(plugin + '.js', function ()
         {
              // This callback is executed when the js file is loaded
              remaining = remaining - 1;
              if (remaining === 0)
              {
                  callback();
              }
         });
    }
}
于 2012-03-22T17:59:04.517 回答