异步实现顺序同步加载资源

乍看之下是个矛盾的命题。


其实并不矛盾

 

异步是什么,大家大都知道就不说了,说说同步顺序加载,也很简单

 

就是假如你有A,B,C三资源需要延迟加载,但又要保证A,B,C之间能顺序加载,同时不阻塞浏览器

 

比如:我们需要加载a,b,c三个js 但是C依赖B,B依赖A,就是说在没有A没有加载完的前提下,如果B中使用了A中的资源那肯定是会出错的。C也是如此。这就有了同

步顺序加载的概念,固使用一般的  (例子都为jQuery,其他AJAX框架应该差别不大)

$.ajax(A);

$.ajax(B);

$.ajax(C); 这样并不能保障ABC会顺序加载完,这样先加载完的会先执行。

 

这样的解决办法很多比如直接<script scr="A.js"></script><script scr="B.js" ></script>。。。这样写在head或者body中,在IE中这是顺序加载的,其他浏览

器不知道是否这样,但这会引出一个问题,会阻塞浏览器,比如我们打开一个网页经常看见白屏很久才出现网页内容, 这就是在头部加载了过多的信息,比如CSS,javascript,也许我们可以把<script src=""> 这个方法body标签最下方。这样可以让页面快速呈现,但当浏览器解释到<script src=""> 时,将依然阻塞浏览器,就是感觉卡住的说。

 

这时需求就出来了,我们希望浏览器不被阻塞,那想到的肯定是异步加载资源。我们可以使用jQuery()的异步加 载,$.ajax(options),其中有一个选项是async询问你是否异步,默认是异步,如果你设置为false 则同步执行,但这并不能解决问题,依然阻塞浏览器。

 

很多童鞋应该都想到了那我们就用回调函数来实现同步顺序加载,也就是这样的形式


$.ajax(A,function(){       $.ajax(B,function(){           $.ajax(C,function(){                   .......                 });     }); });

 

哦,问题出来了,太难看了。你需要顺序加载的资源过多,而且每加载完一个资源需要执行一些处理方法,那么只要这些资源大概上了10个,那么这个缩进 就灰常难看了,而且如果你开发中期需求改变,需要换加一个资源或者删一个资源就悲剧了,眼睛都看花,而且地球人都知道javascript出错,是最悲剧 的,那个找错误啊。

 

这个问题出自我现在正在写的一个个人项目,全凭兴趣而作,下面给出我的解决方案:


function createLoadComponent() {  
    return {   
        textContainer : null,   
        setContainer: function(container){
            this.textContainer=container;
        },   
        println : function(data) {
            this.textContainer.text("开始加载" + data + "...");   
        },   
        dataURLs : new Array(),   
        datasCount : 0,   
        count:0,   
        traverse : function(obj) {    
            if (!obj)     
                obj = this;    
            var dataURL = obj.dataURLs[this.datasCount];    
            if (!dataURL)    {     
                for(var i=0;i<obj.onCompletes.length;i+=1)      
                    obj.onCompletes[i]();    
                this.clear(obj);     
                return;    
            }    
            if (dataURL.name&&obj.textContainer)     
                obj.println(dataURL.name);    
            obj.datasCount += 1;    
            $.ajax( {     
                url : dataURL.url,     
                dataType : dataURL.type ? dataURL.type : "script",     
                success : function(data, textStatus) {      
                    if (dataURL.callBack)        
                        dataURL.callBack(data);      
                    obj.traverse(obj);     
                }    
            });   
        },   
        eventCount:0,   
        ready:function(callBack){    
            this.onCompletes[this.eventCount]=callBack;    
            this.eventCount+=1;   
        },   
        onCompletes:new Array(),   
        addURL:function(_url,_name,_type,_callBack)   {
            this.dataURLs[this.count]={name:_name,url:_url,type:_type,callBack:_callBack};    
            this.count+=1;    
            return this;   
        },   
        clear : function(obj) {    
            if(obj)     
            obj=this;    
            obj==null;   
        }  
    } 
}

 

这是个异步顺序加载器(姑且就这么叫吧)看个使用例子:


var loadComponent = createLoadComponent(); 
loadComponent.addURL("/main.jsp","主页面","html",function(data) {$(document.body).append(data);}); 
loadComponent.addURL("/js/comopent/tooltip/jquery.bgiframe.js","标签提示组件"); 
loadComponent.addURL("/js/comopent/tooltip/jquery.dimensions.js");
loadComponent.addURL("/js/comopent/tooltip/jquery.tooltip.min.js");
loadComponent.addURL("/js/comopent/jquery.validate.js","验证组件");
loadComponent.addURL("/js/utils/messages_cn.js");
loadComponent.addURL("/js/comopent/jquery.cookie.js","cookie组件");
loadComponent.addURL("/js/comopent/jquery.lazyload.js", "延迟加载组件");
loadComponent.addURL("/js/comopent/jquery.simplemodal.js","模式框组件");
loadComponent.addURL("/js/comopent/jquery.quickflip.min.js","Flip组件");
loadComponent.addURL("/js/mode/UserEntity.js","用户实体");
loadComponent.addURL("/js/controller/registController.js","注册控制器");
loadComponent.addURL("/js/controller/loginController.js","登录控制器");
loadComponent.addURL("/js/controller/errorController.js","错误控制器");
loadComponent.setContainer($("#loadtext")); 
loadComponent.ready(initMain); 
loadComponent.traverse();

 

 

下面说下LoadComponent中的方法

setContainer(container)  加载信息输出容器,不设置则不输出,这里的参数为JQuery对象,请在执行traverse()之前调用。 


addURL(url,name,type,callBack)添加一个需加载的脚本,只有URL为必要参数;name为添加的资源名字, 如果你设置了输出容器,则这个名字会在容器中显示,type为资源类型 html, json,xml,script,由于自己项目原因我这里设置了默认值为script,callBack这里的回调方法是加载完该URL所调用的方法。

 

ready(callBack) 完成加载所有脚本后所执行的回调方法,如上述initMain就会在所有资源加载完后执行,可多次使用ready(callBack)添加多个回调方法,按添加顺序执行,请在执行traverse()之前调用。

 

traverse() 开始同步加载添加的所有URL。执行此方法后,会自动执行clear() 方法,释放内存,所以,不要在执行完traverse()方法后继续使用该对象,应从新create一个新对象。

 

注:LoadComponent是基于jquery写的,所以之前还是需要先让浏览器把jquery加载完,但jquery体积还算是比较小的,无所谓了。

 

代码很简单,也可能有很多不完善的地方,但这确实解决了我的问题,如果大家有其他更好解决办法,望不吝赐教。

 

声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值