jQuery ajax —— 将类AJAX方法包装起来

系统 1929 0

上一篇文章 ,将jQuery.ajax中的一些细节补充完。这篇文章讲解如果将类AJAX方法都包装进jQuery.ajax中。下篇文章则讲解各预过滤器和分发器的细节。

 

为什么要包装起来? 

我们知道,古老的XMLHttpRequest出于同源策略考虑,是不支持跨域的。所以,在前端想动态加载跨域Javascript脚本,通常是使用被称为Script DOM Element的方案,如:

      
        var
      
       scriptElem = document.createElement("script"
      
        );
scriptElem.src 
      
      = "http://anydomain.com/A.js"
      
        ;
document.getElementsByTagName(
      
      "head")[0].appendChild(scriptElem);
    

同理,JSON也无法通过XMLHttpRequest进行跨域,所以利用Script DOM Element,将JSON填入一个回调函数中来实现其跨域,也就是JSONP(JSON with padding, 填充式JSON或参数式JSON)。

实际上JSONP就是将,得到JSON后回调的函数通过GET传参告诉服务器,然后服务器拼接一段脚本,用该回调函数并参数为需要的JSON数据,如:

      callback({ "name": "Justany_WhiteSnow" });
    

jQuery团队当然希望开发者开发的时候,不需要想需不需要跨域,只要直接使用就行了。

所以他们把XMLHttpRequest、Script DOM Element、JSONP包装起来,都当成AJAX来使用。

这里顺便提一下,其实现代浏览器(Firefox 3.5+、Safari 4+、Chrome等)中,通过XMLHttpRequeest实现了CORS(Cross-Origin Resource Sharing, 跨源资源共享)原生支持。也就是XMLHttpRequest在某些浏览器中,实际上是可以跨域的,只需要设置一下HTTP Response Header中的Access-Control-Allow-Origin。比如设置成通配符*。

而IE8也引入XDomainRequest也实现了CORS。

但毕竟某些浏览器不行,所以,咳咳……这不能成为一种通用方案。

 

怎么包装起来? 

首先我们有一个山寨XHR对象,也就是jqXHR对象。通过对其添加 send、 abort来模拟XHR对象。

可是我们需要在不同方案执行前先处理一下特异性的东东,所以我们需要一个预过滤机制( Prefilter )来预先处理一下。

然后我们需要知道到底应当用那一套方案来执行整个过程,所以我们需要一个分发机制( Transport )来得到最后的jqXHR对象。

 

inspectPrefiltersOrTransports

我们在jQuery.ajax找到了预过滤和分发机制的函数,inspectPrefiltersOrTransports。

      
        //
      
      
         预过滤
      
      
        inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );


      
      
        //
      
      
        ……
      
      
        //
      
      
         得到transport
      
      
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
    

然后我们看看这个函数在干些什么。

      
        //
      
      
         检测函数,预过滤或者分发器
      
      
        function
      
      
         inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {

    
      
      
        //
      
      
         定义个参数对象
      
      
        var
      
       inspected =
      
         {},
        
      
      
        //
      
      
         看看传进来的结构体是prefilters, 还是transports
      
      
        //
      
      
         如果是prefilters,证明这是预过滤过程,如果是transports分发过程
      
      
        //
      
      
         所以这个是,是不是在分发过程
      
      
        seekingTransport = ( structure ===
      
         transports );

    
      
      
        function
      
      
         inspect( dataType ) {
        
      
      
        var
      
      
         selected;
        
      
      
        //
      
      
         将inspected的dataType对应属性设置成true
      
      
        inspected[ dataType ] = 
      
        true
      
      
        ;
        
      
      
        //
      
      
         遍历prefilters对应dataType对象中的所有过滤器或者转换器工厂函数
      
      
        jQuery.each( structure[ dataType ] || [], 
      
        function
      
      
        ( _, prefilterOrFactory ) {
            
      
      
        //
      
      
         得到dataType或者转换器
      
      
        var
      
       dataTypeOrTransport =
      
         prefilterOrFactory( options, originalOptions, jqXHR );
            
      
      
        //
      
      
         如果dataType为字符串,即上面过程是过滤器
      
      
        //
      
      
         如果在预过滤过程
      
      
        //
      
      
         并且这个过滤出来的dataType不等于刚开始传进来的dataType
      
      
        if
      
      ( 
      
        typeof
      
       dataTypeOrTransport === "string" && !seekingTransport && !
      
        inspected[ dataTypeOrTransport ] ) {
                
      
      
        //
      
      
         将现在这个新的dataType插入到options中
      
      
                        options.dataTypes.unshift( dataTypeOrTransport );
                
      
      
        //
      
      
         检测新的dataType
      
      
                        inspect( dataTypeOrTransport );
                
      
      
        return
      
      
        false
      
      
        ;
            
      
      
        //
      
      
         否则如果在分发过程
      
      
            } 
      
        else
      
      
        if
      
      
         ( seekingTransport ) {
                
      
      
        //
      
      
         定义selected为dataTypeOrTransport
      
      
        return
      
       !( selected =
      
         dataTypeOrTransport );
            }
        });
        
        
      
      
        return
      
      
         selected;
    }

    
      
      
        //
      
      
         检查dataTypes数组的第一个,如果结果是undefined,
      
      
        //
      
      
         则看看上面检查的是不是通配符*,如果不是则检查通配符
      
      
        return
      
       inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*"
      
         );
}
      
    

我们可以看到,这个函数实际上就是从prefilters和transports中取出对应dataType的东东,然后过滤或者分发。

那么怎么定义prefilters和transports这两个对象的呢?

 

jQuery.ajaxPrefilter & jQuery.ajaxTransport

实际上,jQuery是通过这两个接口来定义上面两个对象的内容的,一个是定义预过滤器,另一个则定义分发器。

      jQuery.ajaxPrefilter =
      
         addToPrefiltersOrTransports( prefilters );
jQuery.ajaxTransport 
      
      = addToPrefiltersOrTransports( transports );
    

而这两个方法都是由addToPrefiltersOrTransports生成的。

 

addToPrefiltersOrTransports

      
        //
      
      
         jQuery.ajaxPrefilter和jQuery.ajaxTransport的构造函数
      
      
        function
      
      
         addToPrefiltersOrTransports( structure ) {

    
      
      
        //
      
      
         dataTypeExpression是可选参数,缺省值为*
      
      
        return
      
      
        function
      
      
        ( dataTypeExpression, func ) {
        
        
      
      
        //
      
      
         如果dataTypeExpression不是字符串
      
      
        //
      
      
         模拟重载
      
      
        if
      
       ( 
      
        typeof
      
       dataTypeExpression !== "string"
      
         ) {
            func 
      
      =
      
         dataTypeExpression;
            
      
      
        //
      
      
         缺省为*
      
      
            dataTypeExpression = "*"
      
        ;
        }

        
      
      
        var
      
      
         dataType,
            i 
      
      = 0
      
        ,
            
      
      
        //
      
      
         将dataTypeExpression转为小写,并用空白拆成数组
      
      
            dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) ||
      
         [];

        
      
      
        //
      
      
         如果func是一个函数
      
      
        if
      
      
         ( jQuery.isFunction( func ) ) {
            
      
      
        //
      
      
         遍历dataTypeExpression中的所有dataType
      
      
        while
      
       ( (dataType = dataTypes[i++
      
        ]) ) {
                
      
      
        //
      
      
         如果有必要则删除头部的+号
      
      
        if
      
       ( dataType[0] === "+"
      
         ) {
                    
      
      
        //
      
      
         删除+号
      
      
                    dataType = dataType.slice( 1 ) || "*"
      
        ;
                    
      
      
        //
      
      
         往structure对应的dataType中推入func函数
      
      
                    (structure[ dataType ] = structure[ dataType ] ||
      
         []).unshift( func );

                
      
      
        //
      
      
         否则不需要处理
      
      
                } 
      
        else
      
      
         {
                    
      
      
        //
      
      
         往structure对应的dataType中推入func函数
      
      
                    (structure[ dataType ] = structure[ dataType ] ||
      
         []).push( func );
                }
            }
        }
    };
}
      
    

接下来就是通过调用jQuery.ajaxPrefilter和jQuery.ajaxTransport方法,添加预过滤器和分发器来完成包装。

 

 

 

jQuery ajax —— 将类AJAX方法包装起来


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论