extjs 文件加载、解析流程


extjs版本:4.2.1


  1. 在html中添加应用的启动脚本,如下:

<script src="app.js"></script>

2. 用户访问html的时候,会去加载app.js文件,app中定义了应用的名字,根路径等信息,并且调用Ext.application()方法,如下:

Ext.application({
    name: ‘Seed‘,
    extend: ‘Seed.Application‘,
    autoCreateViewport: true
});



3. Ext.application的详解见 http://wangyuelucky.blog.51cto.com/ 

主要做如下三件事:

  • 设置loader的path

  • 调用Ext.define()

  • 当Ext.onReady的时候,实例化app,代码如下

Ext.onReady(function() {
        // this won‘t be called until App has been created and its requires have been
        // met...
        Ext.app.Application.instance = new App();
    });




4. Ext.define()的详解见 http://wangyuelucky.blog.51cto.com/1011508/1594628 

  主要是调用Manager.create(),实例化生成新的对象new Class(ctor, data, fn);

  其中,var ctor = makeCtor();代码如下:

// Creates a constructor that has nothing extra in its scope chain.
    function makeCtor () { // 什么作用? 工厂模式?
        function constructor () {
            // Opera has some problems returning from a constructor when Dragonfly isn‘t running. The || null seems to
            // be sufficient to stop it misbehaving. Known to be required against 10.53, 11.51 and 11.61.
            return this.constructor.apply(this, arguments) || null;
        }
        return constructor;
    }


  另外,这里的Class就是Ext.Class,代码如下:

(function(Class, alias, arraySlice, arrayFrom, global) {

    var Manager = Ext.ClassManager = {
		create: function(className, data, createdFn) {
		
			// 略
			
            return new Class(ctor, data, /** fn略 */);
        }
	};

}(Ext.Class, Ext.Function.alias, Array.prototype.slice, Ext.Array.from, Ext.global));


5. Ext.Class源码详解http://wangyuelucky.blog.51cto.com/1011508/1594638 

   Ext.Class相当于是构造函数,主要做两件事:

  • 根据构造器ctor和类的配置信息data,调用ExtClass.create()方法,实例化对象并返回

  • 调用ExtClass.process()方法,执行拦截器



6. ExtClass.create(ctor,data)方法非常简单,就是把基类Ext.Base中的静态属性和方法,都复制到ctor上,并返回ctor



7. ExtClass.process(Class, data, onCreated),会执行三类拦截器className,extend,loader,详解见http://wangyuelucky.blog.51cto.com/1011508/1603157,然后执行ExtClass.onBeforeCreated(ctor,data,hooks) // 这里的hook其实就是拦截器 + 4步中的回调函数fn

这里会处理两件事:

  • Class.addMembers(data);

  • hooks.onCreated.call(Class, Class); // 执行4中的回调函数fn




8. 这三类拦截器中,比较复杂的是loader拦截器,详解见http://wangyuelucky.blog.51cto.com/1011508/1603255 

主要作用如下:

  • 按关键字查找当前类的所有直接依赖

  • 检查循环依赖

  • 调用Loader.require(dependencies,fn);加载依赖文件



9. Loader.require()方法详解见http://wangyuelucky.blog.51cto.com/1011508/1594617 

  • 检查依赖文件是否在例外列表中

  • 如果第8步中的回调方法fn,定义了参数,需要把相关对象的引用传递回去

  • 以dependencies数组的形式,把所有的待加载的依赖信息,放入到队列queue中

  • 调用Loader.loadScriptFile(filePath,onFileLoaded); 加载每一个依赖文件,并且标记待加载的文件数+1

Loader.numPendingFiles++;




10. loadScriptFile()方法,就是对同步/异步加载,做一个判断,如果是异步加载,则调用Loader.injectScriptElement()方法



11. Loader.injectScriptElement()方法,会向html中添加<script>标签,并设置回调文件加载、解析成功的函数为第9步中的onFileLoaded,这样每当加载成功一个文件,就执行onFileLoaded()方法



12. onFileLoaded(className, filePath)方法,其实就是标记文件在Loader中的信息

  • 标记类className已经被加载 isClassFileLoaded[className] = true;

  • 标记文件filePath已经被加载 isFileLoaded[filePath] = true;

  • 待加载文件数-1 Loader.numPendingFiles--;

  • 处理missingClasses

  • 当待加载文件数等于0,也就是说loader没有待加载的文件的时候,调用Loader.refreshQueue();


13. Loader.refreshQueue(),详解见http://wangyuelucky.blog.51cto.com/1011508/1604695,该方法会检查queue中的每一个对象的每一个依赖项dependence,是否已经被加载、创建Manager.isCreated(requires[j]).

  • 如果已经被创建则删除此依赖项,如果某个对象的所有依赖项都已经被创建,则从queue中移除该对象。

  • 如果队列queue为空,则调用Loader.triggerReady()方法


注:我这里有几个疑问

  • Loader的待加载数已经为0了,为什么不直接调用Loader.triggerReady()

  • Loader的待加载数已经为0了,就不会再有文件被加载了,也就不会再执行onFileLoaded和refreshQueue方法了,怎么破?


14. Loader.triggerReady()方法,会调用Loader.require()去加载use关键字依赖项。然后执行第3步中的Ext.onReady



序列图:

创建应用 https://www.websequencediagrams.com/?open=72341


加载文件 https://www.websequencediagrams.com/?open=72348


加载完成回调 https://www.websequencediagrams.com/?open=72453


Ext.onReady https://www.websequencediagrams.com/?open=72343 








本文出自 “技术人生” 博客,请务必保留此出处http://wangyuelucky.blog.51cto.com/1011508/1604815

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。