在上一篇javascript動態載入中,提到了使用同步載入策略這一方式來實作如
Using("jquery");
Using("User");
$("#ID").click(function(){
var user = new User();
user.name = "xx";
user.show();
});
由於JS是單線程的,所以同步策略帶來的壞處不少,例如封鎖之後的程式碼運作、造成瀏覽器假死等問題。
使用非同步策略又難以達到先導包 後使用的效果。只能用callback的形式來進行,這又不是UsingJS想要實現的,畢竟jQuery的getScript函數就可以實現這一方式。
經過一番思考,到底怎麼解決導包而且是異步的方式,最後得出一個解決方案。先來看一下採用這個方案後的程式設計方式。
如上程式碼所示,整體來說與同步策略沒有太大的修改,只是導入了兩次jquery,這裡顯然是需要處理成只導包一次,並且裡面增加了一個Using.asyn函數,具體這個函數做什麼用,之後會分析。
都知道,非同步策略,是不影響當前運行的,那麼,我導入的包,假如正在加載,而其後的程式碼也正在運行,兩者之間也剛好存在依賴關係,那麼就會出現異常,怎麼解決這兩者之間的關係,目前唯一的解決方法就是回呼函數。
依照Using的思想,必須是先導包後使用。非同步的解決辦法就是在模組使用之前,並不是真的去進行檔案拉取,而是將需要的JS檔案放置到一個物件當中,例如Array,當有真正需求的時候,再逐個進行載入。來看看
Using("jq"); >Using("jq");
Using("Http");
是怎麼運作的。上一段程式碼
var moduleList = [];
Using.fn = Using.prototype;
Using.fn.initialize= function(module){
!this.exist(moduleList,module) ? moduleList.push(module) : null;
}
這段程式碼是略去上下文,截取的Using的原型中的一個初始化方法,從程式碼得知,其主要的職責就是將需要載入的模組放置到moduleList中,並且進行判斷,假如moduleList中含有目前需要載入的模組,那麼,不進行任何操作。
那麼,什麼時候進行加載呢?這個就用到了之前提到的Using.asyn方法,也就是通知Using,現在需要非同步載入檔案了,而且,在載入完畢之後呼叫Using.asyn函數的回呼函數。同樣上一段程式碼
Using.asyn = function(callback) {
Using.fn.script(callback);
}
從程式碼只能簡要的看出,Using.asyn函數呼叫了Using.fn.script函數,並且將回調函數傳給了它。自然,就需要看看其又是怎麼運作的。
複製程式碼 程式碼如下:
Using.fn.script = function(callback){
var _this = this,
complete = 0,
count = moduleList.length,
len = 0;
if(count return;
}
var loadScript = function(){
while(len _this.ajax(Using.Config [moduleList[len]],function(){
complete ;
if(complete >= count){
callback();
}
});
len ;
}
}
!Using.Config ? _this.ajax("/js/config",function(){
loadScript();
}) : loadScript();
}
先看Using.Config,就是上一篇提到的模組設定文件,以通知Using透過模組名來載入對應的模組檔。
其次就是透過內部函數loadScript來做模組檔案的加載,透過一個計數器complete來判斷目前已經加載了幾個模組,當所有模組加載完畢,則呼叫回調函數。
整合以上程式碼,整個思路就是說,透過Using物件來導包,並記錄,透過Using.asyn來通知Using進行非同步加載,最後由Using.fn.script來實現異步加載並執行回調函數。
也注意到Using.fetch函數,整個函數主要是為了解決當程式碼運行到一定程度或某一個需求才要載入的文件,類似於$.getScript文件,在載入之前會進行判斷,判斷目前需要的模組是否已經載入過,如果載入過則直接執行回呼函數。
這次UsingJS的改動,主要是為了將同步策略改為異步策略,但是同樣遺留有很多問題,比如要進行類似$(document).ready,只在文檔加載完畢的時候才執行,本身來說,實現這個一個效果並不難,而是編寫程式碼時,腦子凌亂了,一時沒辦法解決Using.asyn多次呼叫時,由於異步而產生的多次加載同一個模組,又或者各種莫名其妙的問題,一時沒有了頭緒,故,將此問題後延,一步一步的解決之。
還有便是導包的順序,不能任意順序,當時也想做成任意導包,透過加入依賴關係,來做到由程式碼解決載入順序,但是又想到,這個做法沒有什麼很大的實際意義,編碼人員肯定知道文件之間的依賴關係的,如果編碼的人不知道文件的載入順序,就是使用<script>標籤形式,照樣會出錯,而做成依賴關係不僅增加了Using的體積,更重要的是做了一件重複的事情。不知道這樣理解對不對。</script>