首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > JavaScript >

优化EXTJS的按模块上载JS的性能

2012-10-13 
优化EXTJS的按模块下载JS的性能。最近有不少用户跟我反馈,访问Joffice页面的某些功能,需要等几秒钟才能出来

优化EXTJS的按模块下载JS的性能。
最近有不少用户跟我反馈,访问Joffice页面的某些功能,需要等几秒钟才能出来。鉴于这种情况,在此分析一下原因,同时也给出一些解决方案,可以帮助Joffice 1.2,Joffice 1.3的开发用户解决这种根本的问题,可以让这种按模块下载js速度提高7-8倍,特别是有一些模块需要加载很多js的时候,其下载速度还高更多。

joffice 1.3以前的版本,按模块下载的原理如下:

在此我们以流程管理模块为例:

在App.import.js中定义该模块所依赖的js,如下:

FlowManagerView:[              __ctxPath+'/js/flow/ProTypeForm.js',              __ctxPath+'/js/flow/ProDefinitionForm.js',              __ctxPath+'/js/flow/ProDefinitionView.js',              __ctxPath+'/js/flow/FlowManagerView.js',              __ctxPath+'/js/flow/ProDefinitionDetail.js',              __ctxPath+'/js/flow/ProcessRunStart.js',              __ctxPath+'/js/flow/ProDefinitionSetting.js',              __ctxPath+'/js/flow/MyTaskView.js',              __ctxPath+'/js/flow/ProcessNextForm.js',              __ctxPath+'/js/flow/FormDesignWindow.js',              __ctxPath+'/js/flow/FormEditorWindow.js',              __ctxPath+'/js/flowDesign/FlowDesignerWindow.js'      ]  

在此可以看出,该模块所依赖的js比较多,不过每个js都不大。

当点击左菜单的“流程管理”时,其就通过ScriptMgr来下载其所依赖的js,全部下载完成后,才创建这个流程管理的Panel,并且加到TabCenterPanel中去。

我们的调用下载的js代码如下:
function $ImportJs(viewName,callback,params) {       var b = jsCache[viewName];              if (b != null) {           var view =newView(viewName,params);           callback.call(this, view);           } else {            var jsArr = eval('App.importJs.' + viewName);           if(jsArr==undefined || jsArr.length==0){               try{                   var view = newView(viewName,params);                   callback.call(this, view);               }catch(e){               }               return ;           }           ScriptMgr.load({                       scripts : jsArr,                       callback : function() {                           jsCache[viewName]=0;                           var view = newView(viewName,params);                           callback.call(this, view);                       }           });       }   }  


即我们调用:
$ImportJs('FlowManagerView',function(){         return new FlowManagerView();   });  

当传入FlowManagerView时,告诉我们就是需要在App.Import.js中取出该依赖的js数组,然后传给ScriptMgr的load中的scripts参数,告诉他们我们要完成这些js的加载,并且完成后,创建FlowManagerView对象。

现在我们来看一下ScriptMgr的Load方法:
ScriptLoaderMgr = function() {       this.loader = new ScriptLoader();         this.load = function(o) {           if (!Ext.isArray(o.scripts)) {               o.scripts = [o.scripts];           }             o.url = o.scripts.shift();             if (o.scripts.length == 0) {               this.loader.load(o);           } else {               o.scope = this;               this.loader.load(o, function() {                           this.load(o);                       });           }       };   };  

ScriptLoader的代码如下:
/**   * 用于动态加载js    *  sample is here    *   ScriptMgr.load({    *   scripts: ['/js/other-prerequisite.js', '/js/other.js'],    *   callback: function() {    *     var other = new OtherObject();    *     alert(other); //just loaded    *   }    * });     */  ScriptLoader = function() {       this.timeout = 10;       this.scripts = [];       this.disableCaching = true;//false       this.loadMask = null;   };     ScriptLoader.prototype = {       showMask : function() {           if (!this.loadMask) {               this.loadMask = new Ext.LoadMask(Ext.getBody());               this.loadMask.show();           }       },         hideMask : function() {           if (this.loadMask) {               this.loadMask.hide();               this.loadMask = null;           }       },         processSuccess : function(response) {           this.scripts[response.argument.url] = true;           window.execScript ? window.execScript(response.responseText) : window                   .eval(response.responseText);           //if (response.argument.options.scripts.length == 0) {               this.hideMask();           //}           if (typeof response.argument.callback == 'function') {               response.argument.callback.call(response.argument.scope);           }       },         processFailure : function(response) {           this.hideMask();           Ext.MessageBox.show({                       title : '应用程序出错',                       msg : 'Js脚本库加载出错,服务器可能停止,请联系管理员。',                       closable : false,                       icon : Ext.MessageBox.ERROR,                       minWidth : 200                  });           setTimeout(function() {Ext.MessageBox.hide();}, 3000);       },         load : function(url, callback) {           var cfg, callerScope;          if (typeof url == 'object') { // must be config object               cfg = url;               url = cfg.url;               callback = callback || cfg.callback;               callerScope = cfg.scope;               if (typeof cfg.timeout != 'undefined') {                   this.timeout = cfg.timeout;               }               if (typeof cfg.disableCaching != 'undefined') {                   this.disableCaching = cfg.disableCaching;               }           }             if (this.scripts[url]) {               if (typeof callback == 'function') {                   callback.call(callerScope || window);               }               return null;           }             this.showMask();           //alert('load now?');           Ext.Ajax.request({                       url : url,                       success : this.processSuccess,                       failure : this.processFailure,                       scope : this,                       timeout : (this.timeout * 1000),                       disableCaching : this.disableCaching,                        argument : {                           'url' : url,                           'scope' : callerScope || window,                           'callback' : callback,                           'options' : cfg                       }                   });       }   };  

从以上我们可以看出,其加载的js数组的时候,是加载完成一个js后,然后再加载另一个js,直到加载完成后才调用回调函数。若一个模块有20个js,每个js平均下载的时间需要0.5秒,即就需要10秒钟加载。当然我们可以把这些js合并至一个js,然后下载,这是理论上是可以的,不过不利于代码的划分。

我们知道浏览器是可以同时下载这些js的,只不过我们需要知道什么时候下载完成,下载完成后我们就可以调用回调函数。

鉴于此, 我们通过一个变量来记录其下载js,每完成下载一个就自动加1,若下载完成后,下载的数量就跟我们依赖的js的数量一样,就可以回调,这样我们有多少个js,就产生多少个下载器,每个下载器同时下载这些js,改进后的ScriptMgr的代码如下所示:
ScriptLoaderMgr = function() {       this.loader = new ScriptLoader();       this.load = function(o) {           if (!Ext.isArray(o.scripts)) {               o.scripts = [o.scripts];           }           //记数器           o.lfiles=0;           for(var i=0;i<o.scripts.length;i++){               o.url = o.scripts[i];               o.scope = this;               this.loader.load(o, function() {                   o.lfiles++;                   if(o.lfiles==o.scripts.length){                       if(o.callback!=null){                           this.loader.hideMask();                           o.callback.call(this);                       }                   }               });           }       };   };  


JOfficeOA 2.0电信访问地址:
http://office.jee-soft.cn:8080/login.jsp
JOfficeOA 2.0网通访问地址:
http://oa.jee-soft.cn:8080/login.jsp
账号:admin  密码:1

联系人:廖先生
QQ:571172008
电话:020-61151622

热点排行