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

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

2012-09-22 
优化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);                      });  [size=medium][/size]        }      };  };

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);                      }                  }              });          }      };  };


大家可以在访问体验一下:

  http://oa.jee-soft.cn:8080/index.jsp

  http://office.jee-soft.cn:8080/index.jsp

  user:csx

  pwd 111

热点排行