javascript動態載入三

來源:互聯網
上載者:User

之前兩篇都介紹了,通過動態載入JS檔案或者說JS模組,是怎麼一步一步實現。

首先是通過同步策略來實現模組載入與回呼函數之間進行分離,接著是通過非同步策略來實現模組載入與回呼函數之間進行分離。

這一篇,主要是為了說說怎麼最佳化非同步策略,並且實現了隨意載入(非任意順序載入模組),頁面Ready之後負載檔案。先接一下上一篇遺留下來的問題

1、頁面Ready之後進行載入

2、隨意添加模組 進行載入

看第一個問題,這個問題其實還是比較簡單的,主要是監聽頁面的DOMContentLoaded事件,這裡就不多講解,網路上搜尋,一堆答案,直接上代碼。 複製代碼 代碼如下:Using.ready = function(callback){
readyList.push(callback);

if(document.addEventListener){
document.addEventListener("DOMContentLoaded",_ready,false);
return;
}
// for IE
var domReady = function(){
try{
document.documentElement.doScroll("left");
_ready();
}catch(ex){
setTimeout(domReady,1);
return;
}
}
domReady();
}

這一段代碼中最難以理解的應該就是 複製代碼 代碼如下:document.documentElement.doScroll("left");

這裡其實是IE的頁面載入完畢事件,簡單說就是IE裡面標籤載入完畢之後,是可以操作Scroll的,那就根據此原理來判斷IE中頁面是否載入完畢。

裡面有一個_ready函數,這個函數就是用來做頁面載入完畢之後執行所有載入的函數。貼一下代碼

(編輯一下這一段:頁面載入完畢Ready函數並不是我們思想中所認為的原生JS的window.load,簡單說只是頁面中DOM結構的載入完畢,具體資訊,可自行百度google之) 複製代碼 代碼如下:var readyList = [];
var _ready = function(){
while(readyList.length > 0){
var func = readyList.shift();
func();
}
document.removeEventListener("DOMContentLoaded",_ready,false);
}

下面就是本博文的重點了。還是先看一下代碼 複製代碼 代碼如下:Using.asyn = function(callback){
asynQueue.push(callback);
if(!_execAsyn.isRunning){
_execAsyn();
}
}

還是通知Using要載入所需要的模組了,只不過裡面加入了一個asynQueue數組和_execAsyn函數,他們的作用分別是

asynQueue是用來儲存非同步載入之後要回調的函數,沒什麼好解釋的,是一個數組,可以理解為建立了一個函數的隊列

_execAsyn是用來執行儲存的那些回呼函數的,即將所儲存的函數逐一執行。看一下代碼,代碼中對每行的作用都進行了注釋 複製代碼 代碼如下:var _execAsyn = function(){
// 建立一個變數來緩衝需要執行的函數
var func = null;
// 如果隊列中還有未執行的函數 則進行執行操作
if(asynQueue.length > 0){
// 將_execAsyn函數修改為運行狀態
_execAsyn.isRunning = true;
// 得到隊列中第一個需要執行的函數
func = asynQueue.shift();
// 調用非同步載入模組Using.fn.script函數 並傳入載入完畢之後需要執行的回呼函數
Using.fn.script(function(){
// 當前需要執行的函數
func();
// 迭代_execAsyn 直到隊列中沒有需要執行的函數
_execAsyn();
});
// 若隊列中沒有需要執行的函數
}else{
// 則將_execAsyn運行狀態改為false
_execAsyn.isRunning = false;
}
}

這個函數,解釋起來沒什麼特別的,說白了就是一個一個的執行需要執行的函數。那麼,唯一需要注意的就是為什麼操作隊列的時候沒有採用迴圈,而是使用迭代。那原因就是

1、隊列中隨時可能有新的函數需要執行,採用迴圈的話,可能執行不到最新的函數,因為函數總是插入到隊列的尾部

2、 Using.fn.script是非同步,如果是迴圈的話,當前函數還沒有執行完,可能下一個函數就已經進入了執行狀態。那麼,本身來說,同時執行幾個函數,速率上可能會更高,為什麼這裡還要限制其多個函數並行呢?原因也很簡單,因為每一次執行隊列中的函數,可能都需要載入相應的模組,那麼如果剛好友兩個或者多個依賴相同模組的函數需要執行,而且並存執行,就可能出現同一個模組載入多次,並可能造成後續的函數執行不了,出現異常。

整個UsingJS的核心部分就這些。在其中我加入了Using.Class.create函數,這個函數在javascript動態載入文章的末尾有提到。

最後看一下頁面使用方式: 複製代碼 代碼如下:<script type="text/javascript" src="js/using-0.4.2.min.js"></script>
<script type="text/javascript">
Using("jq");
Using("UserView");
Using("jq");

Using.ready(function(){
Using.asyn(function(){
$("#panel").click(function(){
alert("by jquery");
});
});
});
Using.ready(function(){
Using("Http");
Using.asyn(function(){
var http = new Using.Modules.Http();
http.set("xxx");
http.show();
});
Using.asyn(function(){
var h = new Using.Modules.Http();
h.set("ooo");
h.show();
});
Using("jq");
Using.asyn(function(){
$("#panel").click(function(){
alert("loaded jquery");
});
});
});
</script>

這個一段代碼,刻意進行重複載入,多次Ready事件和Ready之後進行Using導包。

有一個特別需要注意的地方 複製代碼 代碼如下:Using("Http");
Using.asyn(function(){
var http = new Using.Modules.Http();
http.set("xxx");
http.show();
});
// 假如在這個地方使用
// var ht = new Using.Modules.Http();
// 是會報Using.Modules.Http不是一個constructor
// 原因就是
// 任何操作都是非同步,當執行此句時Using("Http")這個模組載入可能還沒有完成
// 這一點是仲謀給多個朋友進行使用時會犯的錯誤 總以為導包之後 萬事大吉
// 是的 本身應該是這樣 導包之後 在任何地方都可以隨意引用
// 但是總得有個前提吧 那就是模組得載入完畢
// 所以 還請將所有的代碼都寫在Using.asyn之內
Using.asyn(function(){
var h = new Using.Modules.Http();
h.set("ooo");
h.show();
});

UsingJS下載

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.