日期:2014-05-16  浏览次数:20329 次

优化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 ? wind