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等函數名稱只會這段空間中有效,不會與網頁其他地方的函數命名衝突,理由是不希望因為插入控件而干擾到網頁其他部分,我認為這也算控件品質的衡量指標之一。

Published 15 January 2009 09:45 AM 由 Jeffrey
Filed under: ,


意見

# tim said on 14 January, 2009 08:47 PM

你的第一段比喻. 還真的很有趣咧. 不過也算傳神了. 厲害厲害. 關於動態載入的做法, 小弟以為, 得看實際上的用途, 寫程式寫久了, 有時候會因為需要一些小功能而大費周章, 但也會因為有了 framework 而蓋更高的大樓了. 真的是要因案施不同工法咧.

# BLACKBING said on 14 January, 2009 09:56 PM

IE不支援script 的onload事件,但是可以用onreadystatechange,透過檢查readyState來判斷是否onload。應該會比setInterval的方式更簡單。

# KINK said on 24 March, 2009 01:11 AM

J大..你好

請問我如果想把這應用在goole的jquery上的話,這段該怎麼處理呢?

<script type="text/javascript" language="javascript">

google.load("jquery", "1.3.2");

</script>

我從firebug只得知jQuery is not defined,但google卻OK?.......動態引入對效能這樣之下,不知道會不會大大折扣了XD

# tad said on 11 May, 2009 01:33 AM

感謝您,這篇文章解決了我長久以來的問題!

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 

請輸入以上的數字:

搜尋

Go

<January 2009>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
 
RSS
【工商服務】

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


BlogLook Score and Rank

Syndication