2012-03-22 58 views
0

我做了一個JavaScript的命名空間框架。我正在加載一些插件(.js文件),這些插件被動態添加到HTML中。檢測腳本列表是否全部用JavaScript加載(使用名稱空間)。

我將盡量簡化代碼。

此函數用於dinamically加載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; 
     } 
}; 

我必須加載包含在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(),以便在所有插件腳本加載後執行回調。

任何想法?也許使用閉包。

回答

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事件可以在腳本加載時觸發。沒有我建議的代碼,回調將被多次調用一個腳本。
+0

PS。如果您還想在沒有插件時調用回調,請添加'if(allPlugins === 0)callback();'。 – 2012-03-22 18:07:47

+0

優秀的答案。我不明白你爲什麼要做回調&&回調()以及爲什麼你在之後將它設置爲null。 – Tony 2012-03-22 18:09:38

+0

@Tony在你的腳本加載器中,你使用'onload' **和''onreadystatechange'事件。當腳本完成加載時,兩者都可以觸發。查看我的更新答案以獲得解釋(另外,使用'onreadystatechange'而不是'onreadystate'。後者是一種不存在的方法。 – 2012-03-22 18:15:11

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(); 
       } 
     }); 
    } 
}