宏天对EXTJS的性能调整:
1.打开Tomcat或Appace的js、html,xml的gzip压缩功能
2.同时用yui工具压缩所有的开发的js,css
3.配置image,js,css的缓存功能
4.用gzip工具压缩超大的js
5、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); } } }); } }; };