YUI3和Extjs,jquery的很大不同就是对于模块的管理,对于使用动态加载脚本的方式来管理模块,记得最早由dojo提出,但是由于实现复杂(Extjs方面自己也尝试过 )且早期web开发多为小项目,就一直没有流行开来,而如今网站越来越复杂,动态加载管理模块的方式对于大团队开发能起到很好的协调作用,今天下午有空就把源码 yui-debug.js 以及 loader-debug.js读了一遍,其中combo的提议确实很精妙,但是也存在了缓存与http连接数的权衡问题: 每个页面js都不相同,如果combo到极度,那么每个页面的脚本必然都不能缓存,若完全没有combo则每个模块一个js的话,页面的http连接数将多得不可接受,不过这个自动combo的思路确实很好,搭配loader的依赖计算,以前恼人的脚本顺序问题迎刃而解。
YUI3基本不再需要依赖domready,只要把use放在页面最后即可,本来就可以保障运行到js时之前的DOM树已经建立完成
1.模块分为加载和attach两步
1.1加载为使用loader载入服务器模块js代码保存到全局YUI中。
1.2.attach是在当前YUI实例上执行模块的初始化代码,使得模块在当前实例上可用。
2.YUI种子文件初始化过程(YUI(config))
1.配置初始参数设置,以及添加自定义模块
2.调用this.use("yui-base")加载 yui-base 模块 ,随之导致加载 yui,yui-later,get模块到YUI.Enc.Mods,并将以上模块attach到当前对象上下文
3.加载模块过程(use)
1.如果该模块之前没有被加载过(YUI.Env.Mods没有)且loader也没加载,则加载loader,回调重新调用use,结束
2.loader加载了,如果该模块之前没有被加载过(YUI.Env.Mods没有),则使用loader计算该模块的依赖项,逐一加载,
2.1 若可以combo,则先combo所有的css加载,调用_internalCallback ,然后combo所有的js加载
2.2 否则挨个加载(使用Y.GET _queue队列),先把所有的css加载完,调用_internalCallback,然后加载所有的js
this._internalCallback = function() { var f = self.onCSS; if (f) { f.call(self.context, Y); } self._internalCallback = null; self._insert(null, null, JS); }; // _queue.running = false; this._insert(null, null, CSS);
最后注意css的特殊处理,有些浏览器css不会报告加载成功状态,则不监控,添加到dom后直接报告成功
// FireFox does not support the onload event for link nodes, so there is // no way to make the css requests synchronous. This means that the css // rules in multiple files could be applied out of order in this browser // if a later request returns before an earlier one. Safari too. if ((ua.webkit || ua.gecko) && q.type === "css") { _next(id, url); }
最后,调用 _onSuccess,由loader attach所有加载模块到当前对象上下文
3.模块被加载过,但是没有attach到当前对象Y上下文,则直接attach即可。
4.模块管理
全局命名空间YUI,保证每个模块被加载一次,但可被attach到多个YUI对象
YUI.Enc.Mods =[{ name: name, fn: fn, //模块初始化的代码 version: version, details: details || {} } ....]
5.添加模块:
YUI.add('loader', function(Y) { //可以在Y上添加模块 Y.Module1=function(){}; },'3.0.0',{ //加载模块前需要载入的模块 requires:[], //当前模块使用的模块 use:[] })
每次YUI().use("module",function(Y){}); 都会生成对象Y再执行模块的初始化代码,添加模块到新生成的Y上,当使用多个use时,由于闭包则会产生内存占用过多问题,最好为对一个模块的使用,放在一个use中.
YUI().use("node",function(Y1){ var n1=Y1.one("#n1"); n1.on("click",function(){alert(Y1);}); }); YUI().use("node",function(Y2){ var n1=Y2.one("#n2"); n1.on("click",function(){alert(Y2);}); });
且 Y1.mix!=Y2.mix
6.Loader动态加载过程
如YUI().use("node") 默认由 yui-loader计算所有缺失项,分个使用Y.Get插入到 head
默认根据页面载入的yui种子script的src来判断base,可以使用combo来降低http连接数,有3个办法
1.自己配置combo,并设置YUI({comboBase})
2.设置base为yahoo:YUI({base:"http://yui.yahooapis.com/3.0.0/build/"})
3.最简单:页面script src直接使用yahoo:<script src="http://yui.yahooapis.com/3.0.0/build/yui/yui-debug.js">
总之如果:o.base && (o.base.indexOf( this.comboBase.substr(0, 20)) > -1); 则会使用combo来加载模块集,如 "node"的加载项
combo?3.0.0/build/oop/oop-min.js&3.0.0/build/dom/dom-min.js&3.0.0/build/event-custom/event-custom-base-min.js&3.0.0/build/event/event-base-min.js&3.0.0/build/pluginhost/pluginhost-min.js&3.0.0/build/node/node-min.js&3.0.0/build/event/event-delegate-min.js