javascript動態(tài)加載三
更新時間:2012年08月22日 22:49:11 作者:
首先是通過同步策略來實現(xiàn)模塊加載與回調(diào)函數(shù)之間進行分離,接著是通過異步策略來實現(xiàn)模塊加載與回調(diào)函數(shù)之間進行分離
之前兩篇都介紹了,通過動態(tài)加載JS文件或者說JS模塊,是怎么一步一步實現(xiàn)。
首先是通過同步策略來實現(xiàn)模塊加載與回調(diào)函數(shù)之間進行分離,接著是通過異步策略來實現(xiàn)模塊加載與回調(diào)函數(shù)之間進行分離。
這一篇,主要是為了說說怎么優(yōu)化異步策略,并且實現(xiàn)了隨意加載(非任意順序加載模塊),頁面Ready之后加載文件。先接一下上一篇遺留下來的問題
1、頁面Ready之后進行加載
2、隨意添加模塊 進行加載
看第一個問題,這個問題其實還是比較簡單的,主要是監(jiān)聽頁面的DOMContentLoaded事件,這里就不多講解,網(wǎng)絡(luò)上搜索,一堆答案,直接上代碼。
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();
}
這一段代碼中最難以理解的應(yīng)該就是
document.documentElement.doScroll("left");
這里其實是IE的頁面加載完畢事件,簡單說就是IE里面標簽加載完畢之后,是可以操作Scroll的,那就根據(jù)此原理來判斷IE中頁面是否加載完畢。
里面有一個_ready函數(shù),這個函數(shù)就是用來做頁面加載完畢之后執(zhí)行所有加載的函數(shù)。貼一下代碼
(編輯一下這一段:頁面加載完畢Ready函數(shù)并不是我們思想中所認為的原生JS的window.load,簡單說只是頁面中DOM結(jié)構(gòu)的加載完畢,具體信息,可自行百度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數(shù)組和_execAsyn函數(shù),他們的作用分別是
asynQueue是用來保存異步加載之后要回調(diào)的函數(shù),沒什么好解釋的,是一個數(shù)組,可以理解為創(chuàng)建了一個函數(shù)的隊列
_execAsyn是用來執(zhí)行保存的那些回調(diào)函數(shù)的,即將所保存的函數(shù)逐一執(zhí)行??匆幌麓a,代碼中對每行的作用都進行了注釋
var _execAsyn = function(){
// 創(chuàng)建一個變量來緩存需要執(zhí)行的函數(shù)
var func = null;
// 如果隊列中還有未執(zhí)行的函數(shù) 則進行執(zhí)行操作
if(asynQueue.length > 0){
// 將_execAsyn函數(shù)修改為運行狀態(tài)
_execAsyn.isRunning = true;
// 得到隊列中第一個需要執(zhí)行的函數(shù)
func = asynQueue.shift();
// 調(diào)用異步加載模塊Using.fn.script函數(shù) 并傳入加載完畢之后需要執(zhí)行的回調(diào)函數(shù)
Using.fn.script(function(){
// 當(dāng)前需要執(zhí)行的函數(shù)
func();
// 迭代_execAsyn 直到隊列中沒有需要執(zhí)行的函數(shù)
_execAsyn();
});
// 若隊列中沒有需要執(zhí)行的函數(shù)
}else{
// 則將_execAsyn運行狀態(tài)改為false
_execAsyn.isRunning = false;
}
}
這個函數(shù),解釋起來沒什么特別的,說白了就是一個一個的執(zhí)行需要執(zhí)行的函數(shù)。那么,唯一需要注意的就是為什么操作隊列的時候沒有采用循環(huán),而是使用迭代。那原因就是
1、隊列中隨時可能有新的函數(shù)需要執(zhí)行,采用循環(huán)的話,可能執(zhí)行不到最新的函數(shù),因為函數(shù)總是插入到隊列的尾部
2、 Using.fn.script是異步的,如果是循環(huán)的話,當(dāng)前函數(shù)還沒有執(zhí)行完,可能下一個函數(shù)就已經(jīng)進入了執(zhí)行狀態(tài)。那么,本身來說,同時執(zhí)行幾個函數(shù),速率上可能會更高,為什么這里還要限制其多個函數(shù)并行呢?原因也很簡單,因為每一次執(zhí)行隊列中的函數(shù),可能都需要加載相應(yīng)的模塊,那么如果剛好友兩個或者多個依賴相同模塊的函數(shù)需要執(zhí)行,而且并行執(zhí)行,就可能出現(xiàn)同一個模塊加載多次,并可能造成后續(xù)的函數(shù)執(zhí)行不了,出現(xiàn)異常。
整個UsingJS的核心部分就這些。在其中我加入了Using.Class.create函數(shù),這個函數(shù)在javascript動態(tài)加載文章的末尾有提到。
最后看一下頁面使用情況:
<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>
這個一段代碼,刻意進行重復(fù)加載,多次Ready事件和Ready之后進行Using導(dǎo)包。
有一個特別需要注意的地方
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
// 原因就是
// 任何操作都是異步的,當(dāng)執(zhí)行此句時Using("Http")這個模塊載入可能還沒有完成
// 這一點是仲謀給多個朋友進行使用時會犯的錯誤 總以為導(dǎo)包之后 萬事大吉
// 是的 本身應(yīng)該是這樣 導(dǎo)包之后 在任何地方都可以隨意引用
// 但是總得有個前提吧 那就是模塊得加載完畢
// 所以 還請將所有的代碼都寫在Using.asyn之內(nèi)
Using.asyn(function(){
var h = new Using.Modules.Http();
h.set("ooo");
h.show();
});
UsingJS下載
首先是通過同步策略來實現(xiàn)模塊加載與回調(diào)函數(shù)之間進行分離,接著是通過異步策略來實現(xiàn)模塊加載與回調(diào)函數(shù)之間進行分離。
這一篇,主要是為了說說怎么優(yōu)化異步策略,并且實現(xiàn)了隨意加載(非任意順序加載模塊),頁面Ready之后加載文件。先接一下上一篇遺留下來的問題
1、頁面Ready之后進行加載
2、隨意添加模塊 進行加載
看第一個問題,這個問題其實還是比較簡單的,主要是監(jiān)聽頁面的DOMContentLoaded事件,這里就不多講解,網(wǎng)絡(luò)上搜索,一堆答案,直接上代碼。
復(fù)制代碼 代碼如下:
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();
}
這一段代碼中最難以理解的應(yīng)該就是
復(fù)制代碼 代碼如下:
document.documentElement.doScroll("left");
這里其實是IE的頁面加載完畢事件,簡單說就是IE里面標簽加載完畢之后,是可以操作Scroll的,那就根據(jù)此原理來判斷IE中頁面是否加載完畢。
里面有一個_ready函數(shù),這個函數(shù)就是用來做頁面加載完畢之后執(zhí)行所有加載的函數(shù)。貼一下代碼
(編輯一下這一段:頁面加載完畢Ready函數(shù)并不是我們思想中所認為的原生JS的window.load,簡單說只是頁面中DOM結(jié)構(gòu)的加載完畢,具體信息,可自行百度google之)
復(fù)制代碼 代碼如下:
var readyList = [];
var _ready = function(){
while(readyList.length > 0){
var func = readyList.shift();
func();
}
document.removeEventListener("DOMContentLoaded",_ready,false);
}
下面就是本博文的重點了。還是先看一下代碼
復(fù)制代碼 代碼如下:
Using.asyn = function(callback){
asynQueue.push(callback);
if(!_execAsyn.isRunning){
_execAsyn();
}
}
還是通知Using要加載所需要的模塊了,只不過里面加入了一個asynQueue數(shù)組和_execAsyn函數(shù),他們的作用分別是
asynQueue是用來保存異步加載之后要回調(diào)的函數(shù),沒什么好解釋的,是一個數(shù)組,可以理解為創(chuàng)建了一個函數(shù)的隊列
_execAsyn是用來執(zhí)行保存的那些回調(diào)函數(shù)的,即將所保存的函數(shù)逐一執(zhí)行??匆幌麓a,代碼中對每行的作用都進行了注釋
復(fù)制代碼 代碼如下:
var _execAsyn = function(){
// 創(chuàng)建一個變量來緩存需要執(zhí)行的函數(shù)
var func = null;
// 如果隊列中還有未執(zhí)行的函數(shù) 則進行執(zhí)行操作
if(asynQueue.length > 0){
// 將_execAsyn函數(shù)修改為運行狀態(tài)
_execAsyn.isRunning = true;
// 得到隊列中第一個需要執(zhí)行的函數(shù)
func = asynQueue.shift();
// 調(diào)用異步加載模塊Using.fn.script函數(shù) 并傳入加載完畢之后需要執(zhí)行的回調(diào)函數(shù)
Using.fn.script(function(){
// 當(dāng)前需要執(zhí)行的函數(shù)
func();
// 迭代_execAsyn 直到隊列中沒有需要執(zhí)行的函數(shù)
_execAsyn();
});
// 若隊列中沒有需要執(zhí)行的函數(shù)
}else{
// 則將_execAsyn運行狀態(tài)改為false
_execAsyn.isRunning = false;
}
}
這個函數(shù),解釋起來沒什么特別的,說白了就是一個一個的執(zhí)行需要執(zhí)行的函數(shù)。那么,唯一需要注意的就是為什么操作隊列的時候沒有采用循環(huán),而是使用迭代。那原因就是
1、隊列中隨時可能有新的函數(shù)需要執(zhí)行,采用循環(huán)的話,可能執(zhí)行不到最新的函數(shù),因為函數(shù)總是插入到隊列的尾部
2、 Using.fn.script是異步的,如果是循環(huán)的話,當(dāng)前函數(shù)還沒有執(zhí)行完,可能下一個函數(shù)就已經(jīng)進入了執(zhí)行狀態(tài)。那么,本身來說,同時執(zhí)行幾個函數(shù),速率上可能會更高,為什么這里還要限制其多個函數(shù)并行呢?原因也很簡單,因為每一次執(zhí)行隊列中的函數(shù),可能都需要加載相應(yīng)的模塊,那么如果剛好友兩個或者多個依賴相同模塊的函數(shù)需要執(zhí)行,而且并行執(zhí)行,就可能出現(xiàn)同一個模塊加載多次,并可能造成后續(xù)的函數(shù)執(zhí)行不了,出現(xiàn)異常。
整個UsingJS的核心部分就這些。在其中我加入了Using.Class.create函數(shù),這個函數(shù)在javascript動態(tài)加載文章的末尾有提到。
最后看一下頁面使用情況:
復(fù)制代碼 代碼如下:
<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>
這個一段代碼,刻意進行重復(fù)加載,多次Ready事件和Ready之后進行Using導(dǎo)包。
有一個特別需要注意的地方
復(fù)制代碼 代碼如下:
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
// 原因就是
// 任何操作都是異步的,當(dāng)執(zhí)行此句時Using("Http")這個模塊載入可能還沒有完成
// 這一點是仲謀給多個朋友進行使用時會犯的錯誤 總以為導(dǎo)包之后 萬事大吉
// 是的 本身應(yīng)該是這樣 導(dǎo)包之后 在任何地方都可以隨意引用
// 但是總得有個前提吧 那就是模塊得加載完畢
// 所以 還請將所有的代碼都寫在Using.asyn之內(nèi)
Using.asyn(function(){
var h = new Using.Modules.Http();
h.set("ooo");
h.show();
});
UsingJS下載
相關(guān)文章
微信小程序如何使用Promise對wx.request()封裝詳解(附完整代碼)
微信小程序的wx.request是微信小程序最早生成的數(shù)據(jù)庫傳輸模式,數(shù)據(jù)傳輸簡單明確,下面這篇文章主要給大家介紹了關(guān)于微信小程序如何使用Promise對wx.request()封裝的相關(guān)資料,需要的朋友可以參考下2023-03-03javascript 原型與原型鏈的理解及應(yīng)用實例分析
這篇文章主要介紹了javascript 原型與原型鏈的理解及應(yīng)用,結(jié)合實例形式分析了javascript原型與原型鏈的具體原理、功能、使用方法及操作注意事項,需要的朋友可以參考下2020-02-02