1. 问题描述:

Ext文件异步加载、解释、执行的问题。因为这里涉及了EXT面向对象,所以需要对EXT类的定义有深入的理解(本文略)。


2. 一个简单的异步加载思路

/**
* 定义需要加载的模块的文件路径
*/
loadUserModule = function (callback) {
    var js = ["/paims/users/User.js"];
    js[js.length] = "/paims/users/UserStore.js";
    js[js.length] = "/paims/users/UserXmlReader.js";
    
    js[js.length] = "/paims/users/UserGridPanel.js";
    js[js.length] = "/paims/users/UserGridPanel_ColumnModel.js";


    loadJs(js, '用户模块', function () { // 调用异步加载方法,加载文件
        callback();
    });
}
/**
* 异步加载JS文件
*/
loadJs = function (jsPath,moduleName,callback) {
    if (Ext.type(js) != 'string') {
        if (js.length == 1) {
            js = js[0];
        } else {
            js = js.shift();
            callback = loadJs;
        }
    }

    Ext.Ajax.request({
        url: '/javascript' + js,
        success: onLoadJs,
        method: 'GET',
        scope: callback
    });
}


/**
* 文件加载完成之后,解释执行
*/
onLoadJs = function (response) {
    eval(response.responseText); // 解释执行JS文件内容,忽略eval的副作用
    this(); // 执行回调
}


3. 运行效果如下:

wKioL1Q4iibxf2MSAAD179w-7Q8336.jpg


注意:这里的文件是顺序加载的,原因是在执行递归方法的时候,有一个时间消耗,大概是50ms,导致任意两次Ajax请求直接的时间间隔至少是50ms。


4.UserStore和UserXmlReader两个文件的内容如下:

Paims.users.UserStore = Ext.extend(Paims.data.XmlStore, {
    constructor: function(load_url, params){
        Paims.users.UserStore.superclass.constructor.call(this, new Paims.users.UserXmlReader(), load_url, params);
    }
});


Paims.users.UserXmlReader = Ext.extend(Paims.data.XmlReader, {
    constructor: function(){
        Paims.users.UserXmlReader.superclass.constructor.call(this, Paims.users.User);
    }
});


观察UserStore的源码可以发现,在UserStore中用到了UserXmlReader类。第一直觉,会认为这里在解释执行UserStore文件的时候会报异常,以为在解释执行UserStore的时候UserXmlReader还没有被加载。事实上,却一切正常。因为,UserStore对UserXmlReader的依赖关系写到了constructor方法里,而方法只进行了解释,没有被执行。


5.深入体会Ext类的定义和执行


修改UserStore类的定义如下:

Paims.users.UserStore = Ext.extend(Paims.data.XmlStore, {
    constructor: function(load_url, params){
        Paims.users.UserStore.superclass.constructor.call(this, new ABC(), load_url, params);
    }
});

UserStore中依赖了一个毫无相关的ABC类(方法)。


加载UserStore文件,并解释执行,一切正常,如下图:

wKiom1Q4jmvTrYDxAAEbXRJCZMc327.jpg


只有当UserStore被实例化,执行constructor方法的时候,才会报错,如下图:

wKioL1Q4kSPBWznnAAFGK4DGzl4810.jpg

这里可以这样理解,在加载文件并解释执行的时候,只是解释执行了最外层方法的内容。如果没有显示的执行调用的话,内层的方法是不会执行了。


比如,上例中解释执行的时候,只是执行了最外层的Ext.extend()方法,内层的constructor方法并不会被执行,所以new ABC()语句也不会被执行(但会被解释)。


6. 对于解释执行的理解:

修改UserStore类的定义如下:

Paims.users.UserStore = Ext.extend(Paims.data.XmlStore, {
    constructor: function(load_url, params){
        Paims.users.UserStore.superclass.constructor.call(this, new ABC(), load_url, params);
    }
});
new ABC(); // 注意


这次,当解释执行UserStore文件的时候会报错,如下图:

wKiom1Q4lPDDX-zmAAHFpwIQaKY392.jpg因为位于最外层的new ABC();被解释执行了。


7. 两个小例子

wKiom1Q4lkfTyg45AAAqoCG0Za4853.jpg

解释执行最外层


wKiom1Q4llnDKlGaAAAsbhOia5g561.jpg

执行内层方法name()


wKiom1Q4nJuy5IAMAAAx_2pCMEM924.jpg

解释执行最外层


wKiom1Q4nKrAaMWzAAArep9SDtY584.jpg

执行方法fn()


总结:虽然JS是边解释边执行,但是没有被显示调用的方法只会被解释,不会被执行,只会被检查编译时错误(语法),不会被检查运行时错误。