在上一篇javascript動態載入中,提到了使用同步載入策略這一個方式來實現如
複製代碼 代碼如下:Using("jquery");
Using("User");
$("#ID").click(function(){
var user = new User();
user.name = "xx";
user.show();
});
由於JS是單線程的,所以同步策略帶來的壞處不少,比如阻止之後的代碼運行、造成瀏覽器假死等問題。
使用非同步策略又難以實現先導包 後使用的效果。只能採用callback的形式來進行,這又不是UsingJS想要實現的,畢竟jQuery的getScript函數就可以實現這一方式。
經過一番思考,到底怎麼解決導包而且是非同步方式,最後得出一個解決方案。先來看一下採用這個方案後的編程方式。 複製代碼 代碼如下:<div id="panel"></div>
<script type="text/javascript" src="js/using-0.4.js"></script>
<script type="text/javascript">
Using("jq");
Using("jq");
Using("Http");
Using.asyn(function(){
$("#panel").click(function(){
alert("Using jquery object");
});
Using.fetch("Http",function(){
var http = new Using.Modules.Http();
http.set("xxx");
http.show();
});
});
</script>
如上代碼所示,總體來說與同步策略沒有太大的修改,只是匯入了兩次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 < 1){
return;
}
var loadScript = function(){
while(len < count){
_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的體積,更重要的是做了一件重複的事情。不知道這樣理解對不對。