標籤:
JS 動態載入指令碼 執行回調
關於在javascript裡面載入其它的js檔案的問題可能很多人都遇到過,但很多朋友可能並不知道怎麼判斷我們要載入的js檔案是否載入完成,如果沒有載入完成我們就調用檔案裡面的函數是不會成功的。本文講解怎麼在js中載入其它js檔案並在載入完成後執行回呼函數。
我們可以動態建立 <script> 元素,然後通過更改它的 src 屬性來載入指令碼,但是怎麼知道這個指令檔載入完成了呢,因為我們有些函數需要在指令碼載入完成生效後才能開始執行。 經過對網路上資源的搜尋,我發現在 IE 瀏覽器中可以使用 <script> 元素的 onreadystatechange 來監控載入狀態的改變,並通過判斷它的 readyState 是 loaded 或 complete 來判斷指令碼是否載入完成。而非 IE 瀏覽器可以使用 onload 來直接判斷指令碼是否載入完成。
一個簡單的實現過程看上去是下面這樣的:
//IE下:var script = document.createElement("script");script.setAttribute("type","text/javascript");script.onreadystatechange = function() { if(this.readyState == "loaded" || this.readyState == "complete"){ alert("載入成功啦!"); }}script.setAttribute("src",scripts[i]);//Opera、FF、Chrome等:var script = document.createElement("script");script.setAttribute("type","text/javascript");script.onload = function() { alert("載入成功啦!");}script.setAttribute("src",scripts[i]);
原理很簡單,根據這兩個簡單的原理,我們進行一些修改,我把改成了兩個函數,分別是串列載入和並行載入指令碼。
當傳一個包含多個JS檔案路徑的數組時,串列載入函數從第一個指令檔載入開始,每載入成功一個便開始載入下一個指令檔,全部載入完成後執行回呼函數。而並行載入是一開始便載入全部的指令檔,也就是他們從同一點開始載入,當全部載入完成後,執行回呼函數。
經過測試,這兩個函數相容目前的所有主流瀏覽器。
/** * 串聯載入指定的指令碼 * 串聯載入[非同步]逐個載入,每個載入完成後載入下一個 * 全部載入完成後執行回調 * @param array|string 指定的指令碼們 * @param function 成功後回調的函數 * @return array 所有產生的指令碼元素對象數組 */function seriesLoadScripts(scripts,callback) { if(typeof(scripts) != "object") var scripts = [scripts]; var HEAD = document.getElementsByTagName("head").item(0) || document.documentElement; var s = new Array(), last = scripts.length - 1, recursiveLoad = function(i) { //遞迴 s[i] = document.createElement("script"); s[i].setAttribute("type","text/javascript"); s[i].onload = s[i].onreadystatechange = function() { //Attach handlers for all browsers if(!/*@[email protected]*/0 || this.readyState == "loaded" || this.readyState == "complete") { this.onload = this.onreadystatechange = null; this.parentNode.removeChild(this); if(i != last) recursiveLoad(i + 1); else if(typeof(callback) == "function") callback(); } } s[i].setAttribute("src",scripts[i]); HEAD.appendChild(s[i]); }; recursiveLoad(0);} /** * 並聯載入指定的指令碼 * 並聯載入[同步]同時載入,不管上個是否載入完成,直接載入全部 * 全部載入完成後執行回調 * @param array|string 指定的指令碼們 * @param function 成功後回調的函數 * @return array 所有產生的指令碼元素對象數組 */ function parallelLoadScripts(scripts,callback) { if(typeof(scripts) != "object") var scripts = [scripts]; var HEAD = document.getElementsByTagName("head").item(0) || document.documentElement, s = new Array(), loaded = 0; for(var i=0; i<scripts.length; i++) { s[i] = document.createElement("script"); s[i].setAttribute("type","text/javascript"); s[i].onload = s[i].onreadystatechange = function() { //Attach handlers for all browsers if(!/*@[email protected]*/0 || this.readyState == "loaded" || this.readyState == "complete") { loaded++; this.onload = this.onreadystatechange = null; this.parentNode.removeChild(this); if(loaded == scripts.length && typeof(callback) == "function") callback(); } }; s[i].setAttribute("src",scripts[i]); HEAD.appendChild(s[i]); }}
在這裡是把 <script> 標籤動態插入到頁面中的 <head> 標籤內部,並且載入完成後標籤元素會被自動移除。 細心的你還會發現,這裡使用了一種稱作條件編譯的方法作為運算式(!/*@[email protected]*/0)來判斷是否非 IE 瀏覽器,關於條件編譯並不是本文的重點,有興趣的您可以上網尋找相關資料進行學習。
這兩個函數的使用方法: 這裡我們聲明了一個陣列變數,裡麵包含了兩個遠端JS檔案地址(當然 <script> 標籤呼叫指令碼是支援跨域的):
var scripts = [ "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", "http://wellstyled.com/files/jquery.debug/jquery.debug.js"];//這兩個檔案分別是 jQuery 1.4.的庫檔案和 jQuery Debug 外掛程式//然後你可以使用下面的方法調用並在成功後執行回調了。seriesLoadScripts(scripts,function(){ /* debug = new $.debug({ posTo : { x:‘right‘, y:‘bottom‘ }, width: ‘480px‘, height: ‘50%‘, itemDivider : ‘<hr>‘, listDOM : ‘all‘ }); */ alert(‘指令碼載入完成啦‘);});
這裡使用的是串聯載入的函數,當然你也可以使用並聯載入函數,這可以根據情況使用,建議每下一個指令碼對上一個指令碼有依賴性的使用串聯載入,否則使用並聯,因為原理上並聯要比串聯快那麼些。
JS 動態載入指令碼 執行回調