讓dojo.require非同步載入小部件
注:本文的技術實現是基於非AMD方式的。
最近用dojo開發了個系統,大約有40個widget,之前的做法是在首頁裡面一開始就通過dojo.require將這40多個小部件引入了,由於是在本機測試,所以一直沒有速度問題,後來部署到外網後發現效率太慢了,最長的一次需要30多秒才能完成頁面初始化。雖然我一開始引入了40多個widget,但是我並不是一上來就new這麼多個小部件,一開始我只用到了三四個小部件,所以只例項化了三四個。後面那37個小部件都是在使用者單擊某些按鈕進行分析完成時例項化的,假設如果使用者沒有進行分析操作,那我這37個widget就白引入了,沒有用到,而且造成頁面初始化時間較長,所以我開始想辦法優化require的機制。
我想達到的效果是:假設有一個小部件A,我想在執行var a = new A()操作之前才執行dojo.require("A"),這樣不會require那些無用的小部件的js檔案,就能最大限度的優化請求。如下所示:
dojo.provide("widgets.B");
dojo.require("widgets.BaseWidget");
dojo.declare("widgets.B",[widgets.BaseWidget],{
templateString:dojo.cache("widgets.B","templates/B.html"),
postCreate:function(){
this.inherited(arguments);
dojo.connect(this.finish,"onclick",this,this.createA);
},
createA:function(){
dojo.require("widgets.A");
var a = new widgets.A();
a.placeAt(dojo.body());
a.startup();
},
startup:function(){
this.inherited(arguments);
}
});
我想在單擊B小部件中的finish按鈕的時候執行createA方法,該方法會首先通過dojo.require("widgets.A")引入A.js,然後執行new操作。事實上這樣確實也可以執行。但是我通過Chrome Developer Tools中的Network發現,在B.js這個檔案被下載到瀏覽器中的時候就已經執行了dojo.require("widgets.A"),奇怪了,我明明寫的是在createA的函式中引入的A的啊,怎麼會提前引入了呢?後來發現dojo的require機制有這麼個特點:當把一個檔案下載到瀏覽器時,dojo會自動查詢該檔案中是否存在dojo.require()這樣的語句,只要發現有,就立馬去執行該語句去請求相應的js檔案,而不管該語句寫在檔案的頭部還是寫在某個函式內部。 但是這樣有個問題,如果在js檔案中寫入了dojo.require("A"),無論這樣程式碼出現在js檔案的哪個位置,dojo都會自己去請求A.js這個檔案,而不是等到執行
createA:function(){
eval("(dojo.re"+"quire('widgets.A'))");
var a = new widgets.A();
a.placeAt(dojo.body());
a.startup();
}
上面我把dojo.require拆分成了dojo.re+quire,這樣dojo自身在B.js檔案中找不到完整的dojo.require字串了,也就不會一開始就去請求A.js檔案了,後來通過Chrome下的Network檢查發現確實是在執行createA的時候才去執行的dojo.require("widgets.A"),哈哈。但是我發現還是存在問題:dojo.require()是非同步方法,不是阻塞式的,所以語句eval("(dojo.re"+"quire('widgets.A'))")執行完後不會停滯,而會立即執行下面的var a = new widgets.A()操作,但是此時A.js還沒有下載到瀏覽器中,造成了windgets.A不存在,導致報錯,這可咋整呢?
為了徹底解決這個問題,我又重新想了下,思路是:還是通過eval的方式動態的去執行dojo.require請求,用setInterval每隔一段時間判斷我請求的A.js檔案是否已經下載到瀏覽器中,如果下載完成了,那麼才執行new widgets.A()操作。
全域性函式如下:
//檢查小部件是否已經載入
function checkWidgetLoaded(widgetName){
var names = widgetName.split(".");
var obj = window;
for(var i=0;i<names.length;i++){
var name = names[i];
obj = obj[name];
if(!obj){
return false;
}
}
var loaded = dojo.isFunction(obj);
return loaded;
}
//按需載入小部件
function loadWidget(widgetName,callback){
var loaded = window.checkWidgetLoaded(widgetName);
if(loaded){
if(dojo.isFunction(callback)){
callback();
}
}
else{
var shelterDom = window.showLoading("Loading...");
eval("(dojo.re"+"quire('"+widgetName+"'))");
var sumTime = 0;
var smallTime = 50;//每隔50毫秒就判斷js檔案是否已經引入到本地
var maxTime = 15000;//超時時間15秒
var handle = setInterval(dojo.hitch(this,function(shelterDom){
var loaded = window.checkWidgetLoaded(widgetName);
if(loaded){
window.hideLoading(shelterDom);
clearInterval(handle);
if(dojo.isFunction(callback)){
callback();
}
}
else{
sumTime += smallTime;
if(sumTime >= maxTime){
window.hideLoading(shelterDom);
clearInterval(handle);
}
}
},shelterDom),smallTime);
}
}
使用方法如下:
createA:function(){
window.loadWidget("widgets.A",dojo.hitch(this,function(){
var a = new widgets.A();
a.placeAt(dojo.body());
a.startup();
}));
}
至此,我們就完成了按需請求小部件js的載入機制,這樣可以大大減少在系統一開始引入的小部件的數量。 相關文章
- 小程式中使用ECharts 非同步載入資料Echarts非同步
- 非阻塞載入指令碼指令碼
- echarts非同步載入Echarts非同步
- dhtmlXTree非同步載入HTML非同步
- webpack 非同步載入原理Web非同步
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 同步、非同步、阻塞、非阻塞非同步
- AssetBoundle載入非預設資源
- 同步非同步 與 阻塞非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 同步、非同步,阻塞、非阻塞理解非同步
- 同步、非同步、阻塞與非阻塞非同步
- 同步、非同步、阻塞和非阻塞非同步
- Javascript非同步載入詳解JavaScript非同步
- [iOS]非同步載入UIImageView—-AsyImageViewiOS非同步UIView
- 小程式分包載入
- 前端效能優化——延遲載入和非同步載入前端優化非同步
- Qt入門(14)——父視窗部件和子視窗部件QT
- [轉]阻塞/非阻塞與同步/非同步非同步
- 同步與非同步 阻塞與非阻塞非同步
- Vue 非同步元件&路由懶載入Vue非同步元件路由
- java zTree非同步載入實戰Java非同步
- java同步非阻塞IOJava
- 非同步和非阻塞非同步
- require.js載入非規範的模組UIJS
- 039.Vue3入門,非同步載入元件,初始時不全部載入,使用時才載入Vue非同步元件
- Git hub載入慢?下載慢?瀏覽慢?幾個小技巧讓你一鍵起飛!Git
- 同步、非同步、阻塞、非阻塞的區別非同步
- webpack模組非同步載入原理解析Web非同步
- react非同步載入元件實現解析React非同步元件
- 載入非同步指令碼的藝術非同步指令碼
- JS指令碼非同步載入淺析JS指令碼非同步
- ajax實現頁面非同步載入非同步
- javascript指令碼非同步載入介紹JavaScript指令碼非同步
- Android 非同步載入——AsyncTask詳談Android非同步
- OC 中非同步順序載入用法非同步
- TS_0001:同步載入資料