首先,Loader有几个重要的属性
queue: [] 存放所有主文件类信息,包括他的依赖文件信息,结构如下: [{requires: ‘Seed.view.MainGrid‘ callback: callback // Loader.require(dependencies,function(){});中的function }] 注意:所有的动态加载文件信息都会被放到队列中 isLoading: 是否在加载 numLoadedFiles: 已经加载完成文件数 numPendingFiles: 待加载文件数 seriptsLoading: 正在加载的文件数 isClassFileLoaded: {} 对象存储了所有的类以及他们是否已经被加载了
当文件加载、解析完成会调用回调方法:
if (‘addEventListener‘ in script ) { script.onload = onLoadFn; } else if (‘readyState‘ in script) { // for <IE9 Compatability script.onreadystatechange = function() { if ( this.readyState == ‘loaded‘ || this.readyState == ‘complete‘ ) { onLoadFn(); } }; } else { script.onload = onLoadFn; }
回调方法,之前也有所涉及,如下:
onFileLoaded: function(className, filePath) { var loaded = isClassFileLoaded[className]; // 文件是否已经被加载过 Loader.numLoadedFiles++; // 已加载数量加1 isClassFileLoaded[className] = true; // 标记文件被加载过 isFileLoaded[filePath] = true; // In FF, when we sync load something that has had a script tag inserted, the load event may // sometimes fire even if we clean it up and set it to null, so check if we‘re already loaded here. if (!loaded) { // 如果文件之前没有被加载过,那么待加载数减1 Loader.numPendingFiles--; } if (Loader.numPendingFiles === 0) { // 当待加载数为0 Loader.refreshQueue(); } // missingClasses的处理,略 }
当待加载数量为0的时候,执行Loader.refreshQueue(),如下:
refreshQueue: function() { var ln = queue.length, i, item, j, requires; // When the queue of loading classes reaches zero, trigger readiness if (!ln && !Loader.scriptsLoading) { // ,递归的结束条件:加载队列为空 return Loader.triggerReady(); // triggerReady见下面 } for (i = 0; i < ln; i++) { // 循环队列中的每一个对象 item = queue[i]; if (item) { requires = item.requires; // Don‘t bother checking when the number of files loaded // is still less than the array length if (requires.length > Loader.numLoadedFiles) { continue; } // Remove any required classes that are loaded for (j = 0; j < requires.length; ) { if (Manager.isCreated(requires[j])) { // 如果某个item的依赖类A已经被创建了,则从item的require中移除他 // Take out from the queue arrayErase(requires, j, 1); } else { j++; } } // If we‘ve ended up with no required classes, call the callback if (item.requires.length === 0) { // 当某个类的所有依赖文件都已经被加载,那么从队列中移除该item arrayErase(queue, i, 1); item.callback.call(item.scope); Loader.refreshQueue();// 递归 break; } } } return Loader; }
refreshQueue()方法的作用,是不停的循环检测,直到所有的类都被加载、执行、创建,之后调用triggerReady()方法,如下:
triggerReady: function() { var listener, refClasses = usedClasses; if (Loader.isLoading) { Loader.isLoading = false; if (refClasses.length !== 0) { // 加载用use关键字引用的路径 // Clone then empty the array to eliminate potential recursive loop issue refClasses = refClasses.slice(); usedClasses.length = 0; // this may immediately call us back if all ‘uses‘ classes // have been loaded Loader.require(refClasses, Loader.triggerReady, Loader); return Loader; } } Ext.Array.sort(readyListeners, comparePriority);// listener排序 // this method can be called with Loader.isLoading either true or false // (can be called with false when all ‘uses‘ classes are already loaded) // this may bypass the above if condition while (readyListeners.length && !Loader.isLoading) { // 逐个调用回调方法 // calls to refreshQueue may re-enter triggerReady // so we cannot necessarily iterate the readyListeners array listener = readyListeners.shift(); listener.fn.call(listener.scope); } return Loader; }
从这里看出:use关键字依赖的类,要等其他关键字依赖的类都加载成功之后才加载。
本文出自 “技术人生” 博客,请务必保留此出处http://wangyuelucky.blog.51cto.com/1011508/1604695
extjs loader success callback源码
原文地址:http://wangyuelucky.blog.51cto.com/1011508/1604695