yui3 loader的串行加载特点

yui3 loader的串行加载特性

yui3 的沙箱机制可以在多人协作开发方面提供很大的便利,常被举的例子之一就是:


重复载入脚本问题:

 

...
//开发者 A
<script src="a.js"></>
<div>
</div>
<script>
//a组件应用
</>

....
//开发者 B
<script src="a.js"></>
<script src="b.js"></>
<div>
</div>
<script>
//a,b组件一起应用
</>

开发者A,B的分离造成了完全没必要的 a 脚本引入,不过好点的是浏览器会缓存,但是更好的解决方案则是a完全不必引入。


yui3 的解决方案:

 

 

...
//开发者 A

<div>
</div>
<script>
//a组件应用
YUI().use("a",function(){
//action 1
});
</>

....
//开发者 B
<div>
</div>
<script>
//a,b组件一起应用
YUI().use("a","b",function(){
//action 2
})
</>

 

虽然通过异步加载,避免了引入了a脚本,但是是否异步加载的 a 对应生成的 script 节点会有两个? action 1与 action 2谁先运行?


在我原先的理解 中,既然是完全独立的沙箱,则现实中由于网络的不确定性 action1,action2的执行顺序不定,并且连续YUI() .use的异步脚本加载应该是完全独立并行的,这样的话是很理想的独立环境,但是由于两次use的互相独立必然会造成 a 的重复加载。

 

 


妥协与解决


yui3 这里不像我想的那样完全独立,而是确实考虑了重复加载情况,将use中的异步部分实际上通过全局队列做成了串行执行,且在每次异步加载前先要剔除当前已经加载过的模块。正是由于上述解决方案,也确定了 action1,action2的顺序一定,一定先action1,后action2,可能有点失望,如果上述例子换成

 

YUI().use("a",function(){
//action 1
})

......
html
......


YUI().use("b",function(){
//action 2
})

 

若同时创建两个脚本节点 a,b添加到文档,并行下载a,b必然能提高整体性能,但是为了保证一般情况下不要重复对同一模块多次从server读取(特别是开启combo情况下),在yui3的解决方案下,则变成了:先生成 a 节点添加到文档,待a脚本载入后,删除b和a相交的模块(这里为空),再生成 b 节点添加到文档,yui3强制实行了串行化。

 

实现:

 

1. 每次use都会调用Loade的insert方法:

 

//全局控制加载队列
_queue          = YUI.Env._loaderQueue,
 
insert: function(o, type) {
        .......
        //异步加载行为加入到队列
        _queue.add(function() {
            self._insert(copy, o, type);
        });
        //如果队列中没有正在执行的东西,就执行否则返回
        this._continue();
}

 

在加载中将队列状态设置为正在执行,加载后设置为执行完毕,并标志加载过的模块到全局对象 。

 

_continue:function(){
//....//标志队列在执行
_queue.running = true;
//....
}


_finish:function(){
//....
//标志队列空闲
_queue.running = false;
//....
}

 

2.而在将要真正创建 script节点进行异步加载前进行已加载模块剔除:

 

 _reduce: function() {
// remove if already loaded
//如果前面 use 过了就从待加载模块列表中删除
}