最近有不少用户跟我反馈,访问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);
}
}
});
}
};
};
大家可以在访问体验一下:
http://oa.jee-soft.cn:8080/index.jsp
http://office.jee-soft.cn:8080/index.jsp
user:csx
pwd 111