CODE-動態依序載入JS
最近在翻修以前寫的控件(Web Control),其中有不少操作互動要靠Javascript處理。
當初還不懂jQuery(更精準點說,是jQuery還沒出生),乖乖用Javascript一行行把功能堆出來。用慣了jQuery後,這回要改寫翻新功能,說實在的,我已喪失直接用Javascript Hard-Code的耐性。就好像跟過大哥,體驗過拿手槍汽油彈在街頭火拼的爽快後,就很難再脫離幫派回去過撿石頭木棍跟人打架的生活。(這比喻一整個怪 >_<)
不過,我遇到了一個難題是,由於控件會被其他開發者引用,是屬於被支配、被指使的人頭角色,無法主控網頁的結構,因此要引用jQuery前必須確認網頁有include jquery.js。比較消極的做法是要求開發者在引用控件時一定要自行Include控件用到的幾個js,不然控件就出錯給你看以示薄懲。
我的野心稍微大一點,希望控件可以聰明地見機行事,若網頁已經載入必要的js,就不必多事,直接給它用下去就對了;否則控件要能自行載入所需的js,以供後續使用。
要實現這個理想,有三個重點: 1) 偵測必要的js是否已載入完成 2) 使用Javascript載入js 3) 多個js必須依序載入(例如: 先jquery.js再jquery.blockUI.js)。
針對1),我們可以檢測特定物件/函數是否存在(例如:typeof jQuery != "undefined")加以判斷。動態載入JS先前有討論過,也不是難事。
第3點比較麻煩,研究了一下,IE似乎無法支援<script>的onload事件,不過我有在網路上找到高人提出的解決方案,利用setInterval持續檢查特定物件是否存在以判定載入完成並觸發後續作業,這樣就可以達成依序逐一載入的目標。(其中interval變數巧妙地運用了Closure技巧,讓我大開眼界。好用的Javascript Closure以後再專文介紹)
綜合上述的研究,我寫成以下的範例:
(function() { function importJS(src, look_for, onload) { var s = document.createElement('script'); s.setAttribute('type', 'text/javascript'); s.setAttribute('src', src); if (onload) wait_for_script_load(look_for, onload);
if (eval("typeof " + look_for) == 'undefined') { var head = document.getElementsByTagName('head')[0]; if (head) head.appendChild(s);
else document.body.appendChild(s);
}
}
function wait_for_script_load(look_for, callback) { var interval = setInterval(function() { if (eval("typeof " + look_for) != 'undefined') { clearInterval(interval);
callback();
}
}, 50);
}
importJS("somePath/jquery-1.2.6.js", "jQuery", function() { importJS("somePath/jquery.blockUI.js", "jQuery.blockUI", function() { $.blockUI({ message: "<span>Done!</span>" }); });
});
})();
註: 最外層我包了一個(function() { ... })();,由於匿名函數的封裝,其中使用的importJS, wait_for_script_load等函數名稱只會這段空間中有效,不會與網頁其他地方的函數命名衝突,理由是不希望因為插入控件而干擾到網頁其他部分,我認為這也算控件品質的衡量指標之一。