天天看点

YUI3 use&Loader 简析

    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