YUI 3 的 loader 已经很优雅地融合在YUI(config).use('moduleName', callback)中:

YUI({
   base: 'http://t-yubo/assets/yui/3.0.0/build/',
   debug: true,
   filter: 'debug',
   modules: {
       jquery: {
           fullpath: 'http://ajax.proxy.ustclug.org/ajax/libs/jquery/1.3/jquery.min.js'
       }
   }
}).use('jquery', 'node', function(Y) {
   jQuery('body').text('YUI kisses jQuery!');
});

config参数,在 yui-base 模块里,原封不动地传给了 Loader:

// use loader to expand dependencies and sort the
// requirements if it is available.
if (Y.Loader) {
    dynamic = true;
    this._useQueue = this._useQueue || new Y.Queue();
    loader = new Y.Loader(Y.config);
    loader.require(a);
    loader.ignoreRegistered = true;
    loader.allowRollup = false;
    loader.calculate();
    a = loader.sorted;
}

注意 debug 和 filter 等参数值,用来切换调试状态非常方便。另外,通过 fullpath, 可以很方便加载任意 js/css 文件。

Loader 的基本工作原理

1. 将 YUI 自带的所有 modules 信息,存放在一个很大的数据对象里:

modules = {
    moduleName: {
        requires: [...],
        optional: [...],
        skinnable: true,
        submodules: { ... },
        plugins: { ... }
    },
    ...
}

2. 根据传入参数和上面的数组,将需要加载的模块按依赖关系排好顺序。核心方法是calculate:

calculate: function(o) {
    if (o || this.dirty) {
        this._config(o);
        this._setup();
        this._explode();
        if (this.allowRollup && !this.combine) {
            this._rollup();
        }
        this._reduce();
        this._sort();

        // Y.log("after calculate: " + this.sorted);

        this.dirty = false;
    }

封装成了 6 个辅助方法,其中_sort方法最考验算法。

3. 按照依赖关系排好顺序的模块信息存放在this.sorted属性中。接下来,调用 get 模块加载即可,具体请参考源码中的_insert, _continue, loadNext等方法。

以上是主线,还有很多细节和分支就不多说了。loader 总共 2000 多行代码,相当不易。

快乐学习,欢迎讨论。