亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

jQuery ajax —— 主函數(shù)分析

系統(tǒng) 2109 0

由于jQuery ajax對(duì)Callbacks、Deferred、serialize、event等模塊的依賴,建議對(duì)這些模塊沒(méi)有認(rèn)識(shí)的朋友看一下 jQuery Callbacks jQuery Deferred jQuery serialize jQuery event(上) jQuery event(下)

這篇文章主要分析的是擁有380+行的jQuery.ajax函數(shù),該函數(shù)是jQuery ajax的核心函數(shù),jQuery的其他ajax方法幾乎都是基于該方法的。

上一篇文章我們了解了Baidu ajax(當(dāng)然是舊版的,還是被簡(jiǎn)化的……),那么我們想給這個(gè)簡(jiǎn)單的ajax方法添加什么功能呢?

?

可鏈?zhǔn)讲僮?

既然是jQuery必然先要解決的是鏈?zhǔn)讲僮鞯膯?wèn)題。

jQuery中的Deferred可以實(shí)現(xiàn)異步鏈?zhǔn)侥P蛯?shí)現(xiàn),Promise對(duì)象可以輕易的綁定成功、失敗、進(jìn)行中三種狀態(tài)的回調(diào)函數(shù),然后通過(guò)在狀態(tài)碼在來(lái)回調(diào)不同的函數(shù)就行了。

?

但僅僅返回一個(gè)promise沒(méi)什么用

promise只能處理異步,我們需要返回一個(gè)更有用的東西。

jqXHR就是這樣的東西,實(shí)際上他是一個(gè)山寨版的XHR對(duì)象。

這樣我們就可以擴(kuò)展一下XHR對(duì)象的功能, 提供一定的容錯(cuò)處理,暴露給外部提供一些方法。

      
        //
      
      
         贗品xhr,或者說(shuō)山寨xhr……╮(╯▽╰)╭
      
      
        
//
      
      
         為了能夠?qū)崿F(xiàn)鏈?zhǔn)讲僮?
      
      
        
//
      
      
         順便擴(kuò)展一下xhr對(duì)象功能
      
      
        
//
      
      
         還有提供一定的容錯(cuò)處理
      
      
jqXHR =
      
         {
    
      
      
        //
      
      
         準(zhǔn)備狀態(tài)
      
      
    readyState: 0
      
        ,

    
      
      
        //
      
      
         如果需要,創(chuàng)建一個(gè)響應(yīng)頭參數(shù)的表
      
      
    getResponseHeader: 
      
        function
      
      
        ( key ) {
        
      
      
        var
      
      
         match;
        
      
      
        //
      
      
         如果狀態(tài)為2,狀態(tài)2表示ajax完成
      
      
        if
      
       ( state === 2
      
         ) {
            
      
      
        //
      
      
         如果沒(méi)有相應(yīng)頭
      
      
        if
      
       ( !
      
        responseHeaders ) {
                
      
      
        //
      
      
         相應(yīng)頭設(shè)空
      
      
                responseHeaders =
      
         {};
                
      
      
        while
      
       ( (match =
      
         rheaders.exec( responseHeadersString )) ) {
                    
      
      
        //
      
      
         組裝相應(yīng)頭
      
      
                    responseHeaders[ match[1].toLowerCase() ] = match[ 2
      
         ];
                }
            }
            
      
      
        //
      
      
         響應(yīng)頭對(duì)應(yīng)的key的值
      
      
            match =
      
         responseHeaders[ key.toLowerCase() ];
        }
        
      
      
        //
      
      
         返回
      
      
        return
      
       match == 
      
        null
      
       ? 
      
        null
      
      
         : match;
    },

    
      
      
        //
      
      
         返回響應(yīng)頭字符串
      
      
    getAllResponseHeaders: 
      
        function
      
      
        () {
        
      
      
        //
      
      
         看看是否接收到了,接收到直接返回,否則為null
      
      
        return
      
       state === 2 ? responseHeadersString : 
      
        null
      
      
        ;
    },

    
      
      
        //
      
      
         設(shè)置請(qǐng)求頭
      
      
    setRequestHeader: 
      
        function
      
      
        ( name, value ) {
        
      
      
        var
      
       lname =
      
         name.toLowerCase();
        
      
      
        //
      
      
         如果state不為0
      
      
        if
      
       ( !
      
        state ) {
            
      
      
        //
      
      
         如果requestHeadersNames[ lname ]不為空,
      
      
        //
      
      
         則requestHeadersNames[ lname ]不變,name設(shè)置為該值
      
      
        //
      
      
         否則,requestHeadersNames[ lname ]不空,
      
      
        //
      
      
         則requestHeadersNames[ lname ]設(shè)置為name,
      
      
        //
      
      
         該映射關(guān)系用于避免用戶大小寫書寫錯(cuò)誤之類的問(wèn)題,容錯(cuò)處理
      
      
            name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] ||
      
         name;
            
      
      
        //
      
      
         現(xiàn)在的name是對(duì)的,或者是第一次設(shè)置這個(gè)name,不需要容錯(cuò)
      
      
        //
      
      
         設(shè)置請(qǐng)求頭對(duì)應(yīng)值
      
      
            requestHeaders[ name ] =
      
         value;
        }
        
      
      
        return
      
      
        this
      
      
        ;
    },

    
      
      
        //
      
      
         重寫相應(yīng)頭content-type
      
      
    overrideMimeType: 
      
        function
      
      
        ( type ) {
        
      
      
        if
      
       ( !
      
        state ) {
            s.mimeType 
      
      =
      
         type;
        }
        
      
      
        return
      
      
        this
      
      
        ;
    },

    
      
      
        //
      
      
         對(duì)應(yīng)狀態(tài)的回調(diào)函數(shù)集
      
      
    statusCode: 
      
        function
      
      
        ( map ) {
        
      
      
        var
      
      
         code;
        
      
      
        //
      
      
         如果map存在,準(zhǔn)備組裝
      
      
        if
      
      
         ( map ) {
            
      
      
        //
      
      
         如果狀態(tài)小于2,表示舊的回調(diào)可能還沒(méi)有用到
      
      
        if
      
       ( state < 2
      
         ) {
                
      
      
        //
      
      
         遍歷map里面的所有code
      
      
        for
      
       ( code 
      
        in
      
      
         map ) {
                    
      
      
        //
      
      
         用類似鏈表的方式添加,以保證舊的回調(diào)依然存在
      
      
                    statusCode[ code ] =
      
         [ statusCode[ code ], map[ code ] ];
                }
            
      
      
        //
      
      
         狀態(tài)大于2,證明已經(jīng)完成了
      
      
            } 
      
        else
      
      
         {
                
      
      
        //
      
      
         無(wú)論Deferred成功還是失敗都執(zhí)行當(dāng)前狀態(tài)回調(diào)
      
      
                        jqXHR.always( map[ jqXHR.status ] );
            }
        }
        
      
      
        return
      
      
        this
      
      
        ;
    },

    
      
      
        //
      
      
         中斷請(qǐng)求
      
      
    abort: 
      
        function
      
      
        ( statusText ) {
        
      
      
        var
      
       finalText = statusText ||
      
         strAbort;
        
      
      
        //
      
      
         可以先理解成XHR對(duì)象,當(dāng)然這也不是真正的XHR對(duì)象
      
      
        if
      
      
         ( transport ) {
            transport.abort( finalText );
        }
        
      
      
        //
      
      
         調(diào)用done,表示干完了
      
      
        done( 0
      
        , finalText );
        
      
      
        return
      
      
        this
      
      
        ;
    }
};
      
    

?

可是這還沒(méi)有鏈?zhǔn)桨。?

怎么把jqXHR變成一個(gè)Promise呢?

讓一個(gè)對(duì)象擁有另一個(gè)對(duì)象的方法,大家會(huì)想到什么呢?

繼承?

不,直接插上去就好了……這里就體現(xiàn)了Javascript“易插拔”的特點(diǎn)……自己亂起的……囧rz……

應(yīng)該說(shuō)動(dòng)態(tài)、弱類的特點(diǎn)。

什么意思?就是將Promise上的方法插到j(luò)qXHR對(duì)象上就行了。

      
        //
      
      
         在jqXHR粘上promise的所有方法,此時(shí)jqXHR就很像一個(gè)promise了
      
      
        //
      
      
         實(shí)際上就是用jQuery.extend(jqXHR, promise)而已
      
      
        //
      
      
         jqXHR剛山寨了xhr對(duì)象,又開(kāi)始山寨promise對(duì)象了
      
      
        //
      
      
         順便把jqXHR的complete綁上completeDeferred.add
      
      
        //
      
      
         意思是jqXHR狀態(tài)完成后調(diào)用completeDeferred這個(gè)Callbacks列隊(duì)
      
      
        //
      
      
         話說(shuō)promise里面并沒(méi)有complete這個(gè)方法
      
      
        //
      
      
         后面我們可以看到,作者大人又要給jqXHR插上complete、success、error方法
      
      
        //
      
      
         Javascript就是這樣簡(jiǎn)單,即插即用……囧rz
      
      
    deferred.promise( jqXHR ).complete =
      
         completeDeferred.add;
    
      
      
        //
      
      
         綁定jqXHR.success為promise里面的done方法
      
      
    jqXHR.success =
      
         jqXHR.done;
    
      
      
        //
      
      
         綁定jqXHR.error為promise里面的fail方法
      
      
    jqXHR.error = jqXHR.fail;
    

這樣子直接插上去在強(qiáng)類語(yǔ)言中是做不到的,當(dāng)然也可以用組合模式來(lái)實(shí)現(xiàn)一個(gè)對(duì)象擁有多個(gè)對(duì)象的方法,但是卻無(wú)法動(dòng)態(tài)的去給對(duì)象添加各種方法。

強(qiáng)類語(yǔ)言會(huì)限制對(duì)象一輩子只能“會(huì)”那么幾種“方法”,Javascript的對(duì)象可以在生命周期內(nèi)隨意“學(xué)習(xí)”各種“方法”。

所以說(shuō),強(qiáng)類語(yǔ)言和Javascript的對(duì)象模型是有差別的,將設(shè)計(jì)模式生搬硬套進(jìn)Javascript或許是錯(cuò)誤的。

我們?cè)倥e個(gè)例子,比如如果用所謂的Javascript組合模式來(lái)重寫上面的代碼可能會(huì)是這樣的:

        
          //
        
        
           定義局部變量deferred和completeDeferred
        
        
          function
        
        
           JQXHR(){
    
        
        
          //
        
        
           定義jqXHR的屬性和方法
        
        
          for
        
        (i 
        
          in
        
        
           deferred.promise){
        
        
        
          this
        
        [i] = 
        
          this
        
        
          .promise[i];
    }
    
        
        
          this
        
        .complete =
        
           completeDeferred.add;
    
        
        
          this
        
        .success = 
        
          this
        
        
          .done;
    
        
        
          this
        
        .error = 
        
          this
        
        
          .done
}


        
        
          var
        
         jqXHR = 
        
          new
        
         JQXHR();
      

大家覺(jué)得哪個(gè)好呢?

變成上面的樣子主要是因?yàn)橐鉀Q下面兩個(gè)問(wèn)題:

  1. jqXHR由于是暴露在外的,他不能包含deferred和completeDeferred,不允許用戶在外部操作這兩個(gè)對(duì)象的狀態(tài)。
  2. deferred和completeDeferred也不能成為jqXHR的私有變量,因?yàn)檫€要更具ajax事件觸發(fā)。

?

提供全局事件,使得UI可以根據(jù)ajax狀態(tài)進(jìn)行改變

這里主要利用了jQuery.event.trigger和jQuery.fn.trigger模擬發(fā)事件。

      
        //
      
      
         如果需要,而且全局事件沒(méi)有被觸發(fā)過(guò)
      
      
        if
      
       ( fireGlobals && jQuery.active++ === 0
      
         ) {
        
      
      
        //
      
      
         則通過(guò)jQuery.event.trigger模擬觸發(fā)
      
      
        jQuery.event.trigger("ajaxStart"
      
        );
    }
      
    

當(dāng)ajax開(kāi)始時(shí)模擬全局事件,ajaxStart。

      
        //
      
      
         如果需要,對(duì)特定對(duì)象觸發(fā)全局事件ajaxSend
      
      
        if
      
      
         ( fireGlobals ) {
            globalEventContext.trigger( 
      
      "ajaxSend"
      
        , [ jqXHR, s ] );
        }
      
    

ajax發(fā)送消息,觸發(fā)ajaxSend。

      
        //
      
      
         如果需要觸發(fā)全局事件
      
      
        if
      
      
         ( fireGlobals ) {
            
      
      
        //
      
      
         對(duì)指定元素觸發(fā)事件ajaxSuccess或者ajaxError
      
      
            globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError"
      
        ,
                [ jqXHR, s, isSuccess 
      
      ?
      
         success : error ] );
        }

        
      
      
        //
      
      
         回調(diào)完成后的Callbacks隊(duì)列
      
      
                completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

        
      
      
        //
      
      
         如果需要觸發(fā)全局事件
      
      
        if
      
      
         ( fireGlobals ) {
            
      
      
        //
      
      
         對(duì)指定元素觸發(fā)事件ajaxComplete
      
      
            globalEventContext.trigger( "ajaxComplete"
      
        , [ jqXHR, s ] );
            
      
      
        //
      
      
         該ajax觸發(fā)完畢,標(biāo)記active減1,如果為0,證明所有ajax結(jié)束
      
      
        if
      
       ( !( --
      
        jQuery.active ) ) {
                
      
      
        //
      
      
         觸發(fā)ajaxStop事件
      
      
                jQuery.event.trigger("ajaxStop"
      
        );
            }
        }    
      
    

結(jié)束時(shí)候觸發(fā)ajaxSuccess或ajaxError,再出發(fā)ajaxComplete,如果全部ajax結(jié)束則觸發(fā)ajaxStop。

?

?

是否允許使用緩存數(shù)據(jù)

      
        //
      
      
         如果不需要content
      
      
        //
      
      
         看看需不需要加其他信息
      
      
        if
      
       ( !
      
        s.hasContent ) {

        
      
      
        //
      
      
         如果data存在,那么已經(jīng)序列化
      
      
        if
      
      
         ( s.data ) {
            
      
      
        //
      
      
         添加到cacheURL中
      
      
            cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) +
      
         s.data );
            
      
      
        //
      
      
         刪除掉則后面就不會(huì)被發(fā)送出去了
      
      
        delete
      
      
         s.data;
        }

        
      
      
        //
      
      
         看看是否需要避免數(shù)據(jù)從緩存中讀取
      
      
        if
      
       ( s.cache === 
      
        false
      
      
         ) {
        
            s.url 
      
      = rts.test( cacheURL ) ?

                
      
        //
      
      
         如果已經(jīng)有_參數(shù),那么設(shè)置他的值
      
      
                cacheURL.replace( rts, "$1_=" + ajax_nonce++
      
         ) :

                
      
      
        //
      
      
         否則添加一個(gè)_ = xxx在URL后面
      
      
                cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++
      
        ;
        }
    }
      
    

通過(guò)給地址附加參數(shù)_=xxx來(lái)避免緩存。

      
        //
      
      
         看看需不需要設(shè)置If-Modified-Since和If-None-Match頭信息
      
      
        if
      
      
         ( s.ifModified ) {
        
      
      
        if
      
      
         ( jQuery.lastModified[ cacheURL ] ) {
            jqXHR.setRequestHeader( 
      
      "If-Modified-Since"
      
        , jQuery.lastModified[ cacheURL ] );
        }
        
      
      
        if
      
      
         ( jQuery.etag[ cacheURL ] ) {
            jqXHR.setRequestHeader( 
      
      "If-None-Match"
      
        , jQuery.etag[ cacheURL ] );
        }
    }
      
    

以及設(shè)置If-Modified-Since和If-None-Match頭信息。

      
        //
      
      
         看看是否需要緩存置If-Modified-Since和If-None-Match頭
      
      
        if
      
      
         ( s.ifModified ) {
        
      
      
        //
      
      
         取得Last-Modified
      
      
        modified = jqXHR.getResponseHeader("Last-Modified"
      
        );
        
      
      
        //
      
      
         如果Last-Modified存在
      
      
        if
      
      
         ( modified ) {
            
      
      
        //
      
      
         在jQuery.lastModified[cacheURL]保存Last-Modified
      
      
            jQuery.lastModified[ cacheURL ] =
      
         modified;
        }
        
      
      
        //
      
      
         取得etag
      
      
        modified = jqXHR.getResponseHeader("etag"
      
        );
        
      
      
        //
      
      
         如果etag存在
      
      
        if
      
      
         ( modified ) {
            
      
      
        //
      
      
         在jQuery.etag[cacheURL]緩存etag
      
      
            jQuery.etag[ cacheURL ] =
      
         modified;
        }
    }
      
    

緩存 If-Modified-Since和If-None-Match頭信息。

?

設(shè)置超時(shí)

      
        //
      
      
         如果是異步,并且設(shè)置了超時(shí)
      
      
        if
      
       ( s.async && s.timeout > 0
      
         ) {
            
      
      
        //
      
      
         設(shè)置超時(shí)
      
      
            timeoutTimer = setTimeout(
      
        function
      
      
        () {
                jqXHR.abort(
      
      "timeout"
      
        );
            }, s.timeout );
        }
      
    

主要功能分析完了,完整備注代碼見(jiàn)下。?

?

完整備注

      jQuery.ajax = 
      
        function
      
      
        ( url, options ) {

    
      
      
        //
      
      
         如果url是一個(gè)obj,模擬1.5版本以前的方法
      
      
        if
      
       ( 
      
        typeof
      
       url === "object"
      
         ) {
        options 
      
      =
      
         url;
        url 
      
      =
      
         undefined;
    }

    
      
      
        //
      
      
         設(shè)置options
      
      
    options = options ||
      
         {};

    
      
      
        var
      
      
         transport,
        
      
      
        //
      
      
         緩存cacheURL
      
      
                cacheURL,
        
      
      
        //
      
      
         響應(yīng)頭
      
      
                responseHeadersString,
        responseHeaders,
        
      
      
        //
      
      
         超時(shí)控制器
      
      
                timeoutTimer,
        
      
      
        //
      
      
         跨域判定變量
      
      
                parts,
        
      
      
        //
      
      
         是否需要觸發(fā)全局事件
      
      
                fireGlobals,
        
      
      
        //
      
      
         循環(huán)變量
      
      
                i,
        
      
      
        //
      
      
         通過(guò)jQuery.ajaxSetup改造參數(shù)對(duì)象
      
      
        s =
      
         jQuery.ajaxSetup( {}, options ),
        
      
      
        //
      
      
         回調(diào)指定上下文,也就是他的this
      
      
        callbackContext = s.context ||
      
         s,
        
      
      
        //
      
      
         全局事件中的相應(yīng)函數(shù)的指定上下文
      
      
        //
      
      
         有s.context,且是DOM節(jié)點(diǎn),或者jQuery收集器
      
      
        globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
            
      
        //
      
      
         通過(guò)jQuery包裝
      
      
                    jQuery( callbackContext ) :
            
      
      
        //
      
      
         否則為jQuery.event
      
      
                    jQuery.event,
        
      
      
        //
      
      
         新建一個(gè)deferred
      
      
        deferred =
      
         jQuery.Deferred(),
        
      
      
        //
      
      
         deferred完成后的Callbacks隊(duì)列
      
      
        completeDeferred = jQuery.Callbacks("once memory"
      
        ),
        
      
      
        //
      
      
         對(duì)應(yīng)狀態(tài)的回調(diào)函數(shù)集
      
      
        statusCode = s.statusCode ||
      
         {},
        
      
      
        //
      
      
         請(qǐng)求頭
      
      
        requestHeaders =
      
         {},
        requestHeadersNames 
      
      =
      
         {},
        
      
      
        //
      
      
         包裝類jqXHR的狀態(tài)
      
      
        state = 0
      
        ,
        
      
      
        //
      
      
         默認(rèn)中斷消息
      
      
        strAbort = "canceled"
      
        ,
        
      
      
        //
      
      
         贗品xhr,或者說(shuō)山寨xhr……╮(╯▽╰)╭
      
      
        //
      
      
         為了能夠?qū)崿F(xiàn)鏈?zhǔn)讲僮?
      
      
        //
      
      
         順便擴(kuò)展一下xhr對(duì)象功能
      
      
        //
      
      
         還有提供一定的容錯(cuò)處理
      
      
        jqXHR =
      
         {
            
      
      
        //
      
      
         準(zhǔn)備狀態(tài)
      
      
            readyState: 0
      
        ,

            
      
      
        //
      
      
         如果需要,創(chuàng)建一個(gè)響應(yīng)頭參數(shù)的表
      
      
            getResponseHeader: 
      
        function
      
      
        ( key ) {
                
      
      
        var
      
      
         match;
                
      
      
        //
      
      
         如果狀態(tài)為2,狀態(tài)2表示ajax完成
      
      
        if
      
       ( state === 2
      
         ) {
                    
      
      
        //
      
      
         如果沒(méi)有相應(yīng)頭
      
      
        if
      
       ( !
      
        responseHeaders ) {
                        
      
      
        //
      
      
         相應(yīng)頭設(shè)空
      
      
                        responseHeaders =
      
         {};
                        
      
      
        while
      
       ( (match =
      
         rheaders.exec( responseHeadersString )) ) {
                            
      
      
        //
      
      
         組裝相應(yīng)頭
      
      
                            responseHeaders[ match[1].toLowerCase() ] = match[ 2
      
         ];
                        }
                    }
                    
      
      
        //
      
      
         響應(yīng)頭對(duì)應(yīng)的key的值
      
      
                    match =
      
         responseHeaders[ key.toLowerCase() ];
                }
                
      
      
        //
      
      
         返回
      
      
        return
      
       match == 
      
        null
      
       ? 
      
        null
      
      
         : match;
            },

            
      
      
        //
      
      
         返回響應(yīng)頭字符串
      
      
            getAllResponseHeaders: 
      
        function
      
      
        () {
                
      
      
        //
      
      
         看看是否接收到了,接收到直接返回,否則為null
      
      
        return
      
       state === 2 ? responseHeadersString : 
      
        null
      
      
        ;
            },

            
      
      
        //
      
      
         緩存請(qǐng)求頭
      
      
            setRequestHeader: 
      
        function
      
      
        ( name, value ) {
                
      
      
        var
      
       lname =
      
         name.toLowerCase();
                
      
      
        //
      
      
         如果state不為0
      
      
        if
      
       ( !
      
        state ) {
                    
      
      
        //
      
      
         如果requestHeadersNames[ lname ]不為空,
      
      
        //
      
      
         則requestHeadersNames[ lname ]不變,name設(shè)置為該值
      
      
        //
      
      
         否則,requestHeadersNames[ lname ]不空,
      
      
        //
      
      
         則requestHeadersNames[ lname ]設(shè)置為name,
      
      
        //
      
      
         該映射關(guān)系用于避免用戶大小寫書寫錯(cuò)誤之類的問(wèn)題,容錯(cuò)處理
      
      
                    name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] ||
      
         name;
                    
      
      
        //
      
      
         現(xiàn)在的name是對(duì)的,或者是第一次設(shè)置這個(gè)name,不需要容錯(cuò)
      
      
        //
      
      
         設(shè)置請(qǐng)求頭對(duì)應(yīng)值
      
      
                    requestHeaders[ name ] =
      
         value;
                }
                
      
      
        return
      
      
        this
      
      
        ;
            },

            
      
      
        //
      
      
         重寫相應(yīng)頭content-type
      
      
            overrideMimeType: 
      
        function
      
      
        ( type ) {
                
      
      
        if
      
       ( !
      
        state ) {
                    s.mimeType 
      
      =
      
         type;
                }
                
      
      
        return
      
      
        this
      
      
        ;
            },

            
      
      
        //
      
      
         對(duì)應(yīng)狀態(tài)的回調(diào)函數(shù)集
      
      
            statusCode: 
      
        function
      
      
        ( map ) {
                
      
      
        var
      
      
         code;
                
      
      
        //
      
      
         如果map存在,準(zhǔn)備組裝
      
      
        if
      
      
         ( map ) {
                    
      
      
        //
      
      
         如果狀態(tài)小于2,表示舊的回調(diào)可能還沒(méi)有用到
      
      
        if
      
       ( state < 2
      
         ) {
                        
      
      
        //
      
      
         遍歷map里面的所有code
      
      
        for
      
       ( code 
      
        in
      
      
         map ) {
                            
      
      
        //
      
      
         用類似鏈表的方式添加,以保證舊的回調(diào)依然存在
      
      
                            statusCode[ code ] =
      
         [ statusCode[ code ], map[ code ] ];
                        }
                    
      
      
        //
      
      
         狀態(tài)大于2,證明已經(jīng)完成了
      
      
                    } 
      
        else
      
      
         {
                        
      
      
        //
      
      
         無(wú)論Deferred成功還是失敗都執(zhí)行當(dāng)前狀態(tài)回調(diào)
      
      
                                jqXHR.always( map[ jqXHR.status ] );
                    }
                }
                
      
      
        return
      
      
        this
      
      
        ;
            },

            
      
      
        //
      
      
         中斷請(qǐng)求
      
      
            abort: 
      
        function
      
      
        ( statusText ) {
                
      
      
        var
      
       finalText = statusText ||
      
         strAbort;
                
      
      
        //
      
      
         可以先理解成XHR對(duì)象,當(dāng)然這也不是真正的XHR對(duì)象
      
      
        if
      
      
         ( transport ) {
                    transport.abort( finalText );
                }
                
      
      
        //
      
      
         調(diào)用done,表示干完了
      
      
                done( 0
      
        , finalText );
                
      
      
        return
      
      
        this
      
      
        ;
            }
        };

    
      
      
        //
      
      
         在jqXHR粘上promise的所有方法,此時(shí)jqXHR就很像一個(gè)promise了
      
      
        //
      
      
         實(shí)際上就是用jQuery.extend(jqXHR, promise)而已
      
      
        //
      
      
         jqXHR剛山寨了xhr對(duì)象,又開(kāi)始山寨promise對(duì)象了
      
      
        //
      
      
         順便把jqXHR的complete綁上completeDeferred.add
      
      
        //
      
      
         意思是jqXHR狀態(tài)完成后調(diào)用completeDeferred這個(gè)Callbacks列隊(duì)
      
      
        //
      
      
         話說(shuō)promise里面并沒(méi)有complete這個(gè)方法
      
      
        //
      
      
         后面我們可以看到,作者大人又要給jqXHR插上complete、success、error方法
      
      
        //
      
      
         Javascript就是這樣簡(jiǎn)單,即插即用……囧rz
      
      
    deferred.promise( jqXHR ).complete =
      
         completeDeferred.add;
    
      
      
        //
      
      
         綁定jqXHR.success為promise里面的done方法
      
      
    jqXHR.success =
      
         jqXHR.done;
    
      
      
        //
      
      
         綁定jqXHR.error為promise里面的fail方法
      
      
    jqXHR.error =
      
         jqXHR.fail;

    
      
      
        //
      
      
         確定url參數(shù),否則用當(dāng)前地址。將地址的#號(hào)后面的所有東西去掉
      
      
        //
      
      
         比如http://127.0.0.1#main,去掉這個(gè)#main
      
      
        //
      
      
         如果開(kāi)頭是//,及數(shù)據(jù)傳輸協(xié)議沒(méi)有,那么用當(dāng)前頁(yè)面的數(shù)據(jù)傳輸協(xié)議替換
      
      
        //
      
      
         比如//127.0.0.1,變成http://127.0.0.1
      
      
    s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "http://"
      
         );

    
      
      
        //
      
      
         定義type,向后兼容
      
      
    s.type = options.method || options.type || s.method ||
      
         s.type;

    
      
      
        //
      
      
         取出數(shù)據(jù)類型列表
      
      
        //
      
      
         沒(méi)有則為"*",
      
      
        //
      
      
         有則認(rèn)為是用空格分隔的字符串,將其變成數(shù)組
      
      
    s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""
      
        ];

    
      
      
        //
      
      
         當(dāng)協(xié)議、主機(jī)、端口和當(dāng)前不匹配時(shí),證明這是一個(gè)跨域請(qǐng)求
      
      
        if
      
       ( s.crossDomain == 
      
        null
      
      
         ) {
        
      
      
        //
      
      
         分隔當(dāng)前url
      
      
        parts =
      
         rurl.exec( s.url.toLowerCase() );
        
      
      
        //
      
      
         判定是否是跨域
      
      
        s.crossDomain = !!( parts &&
      
        
            ( parts[ 
      
      1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
      
        
                ( parts[ 
      
      3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
      
        
                    ( ajaxLocParts[ 
      
      3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443
      
         ) ) )
        );
    }

    
      
      
        //
      
      
         如果data已經(jīng)是一個(gè)字符串了,那么就不用轉(zhuǎn)換了
      
      
        if
      
       ( s.data && s.processData && 
      
        typeof
      
       s.data !== "string"
      
         ) {
        
      
      
        //
      
      
         序列化
      
      
        s.data =
      
         jQuery.param( s.data, s.traditional );
    }

    
      
      
        //
      
      
         預(yù)過(guò)濾
      
      
            inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

    
      
      
        //
      
      
         如果請(qǐng)求被prefilter終止,則退出
      
      
        if
      
       ( state === 2
      
         ) {
        
      
      
        return
      
      
         jqXHR;
    }

    
      
      
        //
      
      
         看看需不需要觸發(fā)全局事件
      
      
    fireGlobals =
      
         s.global;

    
      
      
        //
      
      
         如果需要,而且全局事件沒(méi)有被觸發(fā)過(guò)
      
      
        if
      
       ( fireGlobals && jQuery.active++ === 0
      
         ) {
        
      
      
        //
      
      
         則通過(guò)jQuery.event.trigger模擬觸發(fā)
      
      
        jQuery.event.trigger("ajaxStart"
      
        );
    }

    
      
      
        //
      
      
         將類型大寫
      
      
    s.type =
      
         s.type.toUpperCase();

    
      
      
        //
      
      
         判斷需不需要設(shè)置content
      
      
    s.hasContent = !
      
        rnoContent.test( s.type );

    
      
      
        //
      
      
         緩存URL,用來(lái)在之后設(shè)置If-Modified-Since和If-None-Match
      
      
    cacheURL =
      
         s.url;

    
      
      
        //
      
      
         如果不需要content
      
      
        //
      
      
         看看需不需要加其他信息
      
      
        if
      
       ( !
      
        s.hasContent ) {

        
      
      
        //
      
      
         如果data存在,那么已經(jīng)序列化
      
      
        if
      
      
         ( s.data ) {
            
      
      
        //
      
      
         添加到cacheURL中
      
      
            cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) +
      
         s.data );
            
      
      
        //
      
      
         刪除掉則后面就不會(huì)被發(fā)送出去了
      
      
        delete
      
      
         s.data;
        }

        
      
      
        //
      
      
         看看是否需要避免數(shù)據(jù)從緩存中讀取
      
      
        if
      
       ( s.cache === 
      
        false
      
      
         ) {
        
            s.url 
      
      = rts.test( cacheURL ) ?

                
      
        //
      
      
         如果已經(jīng)有_參數(shù),那么設(shè)置他的值
      
      
                cacheURL.replace( rts, "$1_=" + ajax_nonce++
      
         ) :

                
      
      
        //
      
      
         否則添加一個(gè)_ = xxx在URL后面
      
      
                cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++
      
        ;
        }
    }

    
      
      
        //
      
      
         看看需不需要設(shè)置If-Modified-Since和If-None-Match頭信息
      
      
        if
      
      
         ( s.ifModified ) {
        
      
      
        if
      
      
         ( jQuery.lastModified[ cacheURL ] ) {
            jqXHR.setRequestHeader( 
      
      "If-Modified-Since"
      
        , jQuery.lastModified[ cacheURL ] );
        }
        
      
      
        if
      
      
         ( jQuery.etag[ cacheURL ] ) {
            jqXHR.setRequestHeader( 
      
      "If-None-Match"
      
        , jQuery.etag[ cacheURL ] );
        }
    }

    
      
      
        //
      
      
         如果數(shù)據(jù)需要被發(fā)送,設(shè)置正確的頭
      
      
        if
      
       ( s.data && s.hasContent && s.contentType !== 
      
        false
      
       ||
      
         options.contentType ) {
        jqXHR.setRequestHeader( 
      
      "Content-Type"
      
        , s.contentType );
    }

    
      
      
        //
      
      
         根據(jù)dataType,設(shè)置一個(gè)Accept頭
      
      
            jqXHR.setRequestHeader(
        
      
      "Accept"
      
        ,
        s.dataTypes[ 
      
      0 ] && s.accepts[ s.dataTypes[0] ] ?
      
        
            s.accepts[ s.dataTypes[
      
      0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : ""
      
         ) :
            s.accepts[ 
      
      "*"
      
         ]
    };

    
      
      
        //
      
      
         遍歷s.headers,將其內(nèi)參數(shù)設(shè)置入請(qǐng)求頭
      
      
        for
      
       ( i 
      
        in
      
      
         s.headers ) {
        jqXHR.setRequestHeader( i, s.headers[ i ] );
    }

    
      
      
        //
      
      
         通過(guò)beforeSend檢查是否需要發(fā)送
      
      
        if
      
       ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === 
      
        false
      
       || state === 2
      
         ) ) {
        
      
      
        //
      
      
         終止
      
      
        return
      
      
         jqXHR.abort();
    }

    
      
      
        //
      
      
         此時(shí)abort函數(shù)不是取消ajax,而是中斷了ajax
      
      
    strAbort = "abort"
      
        ;

    
      
      
        //
      
      
         在jqXHR上綁定成功、錯(cuò)誤、完成回調(diào)函數(shù)
      
      
        for
      
       ( i 
      
        in
      
       { success: 1, error: 1, complete: 1
      
         } ) {
        jqXHR[ i ]( s[ i ] );
    }

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

    
      
      
        //
      
      
         如果沒(méi)有,自動(dòng)終止
      
      
        if
      
       ( !
      
        transport ) {
        done( 
      
      -1, "No Transport"
      
         );
    } 
      
      
        else
      
      
         {
        
      
      
        //
      
      
         否則,設(shè)置reayState為1
      
      
        jqXHR.readyState = 1
      
        ;
        
        
      
      
        //
      
      
         如果需要,對(duì)特定對(duì)象觸發(fā)全局事件ajaxSend
      
      
        if
      
      
         ( fireGlobals ) {
            globalEventContext.trigger( 
      
      "ajaxSend"
      
        , [ jqXHR, s ] );
        }
        
      
      
        //
      
      
         如果是異步,并且設(shè)置了超時(shí)
      
      
        if
      
       ( s.async && s.timeout > 0
      
         ) {
            
      
      
        //
      
      
         設(shè)置超時(shí)
      
      
            timeoutTimer = setTimeout(
      
        function
      
      
        () {
                jqXHR.abort(
      
      "timeout"
      
        );
            }, s.timeout );
        }

        
      
      
        try
      
      
         {
            
      
      
        //
      
      
         設(shè)置state為1
      
      
            state = 1
      
        ;
            
      
      
        //
      
      
         開(kāi)始發(fā)送
      
      
                    transport.send( requestHeaders, done );
        } 
      
      
        catch
      
      
         ( e ) {
            
      
      
        //
      
      
         截獲錯(cuò)誤,如果ajax未完成
      
      
        if
      
       ( state < 2
      
         ) {
                done( 
      
      -1
      
        , e );
            
      
      
        //
      
      
         完成了就直接拋出錯(cuò)誤
      
      
            } 
      
        else
      
      
         {
                
      
      
        throw
      
      
         e;
            }
        }
    }

    
      
      
        //
      
      
         完成時(shí)的回調(diào)函數(shù)
      
      
        function
      
      
         done( status, nativeStatusText, responses, headers ) {
        
      
      
        var
      
      
         isSuccess, success, error, response, modified,
            statusText 
      
      =
      
         nativeStatusText;

        
      
      
        //
      
      
         如果已經(jīng)調(diào)用過(guò)該函數(shù),直接退出
      
      
        if
      
       ( state === 2
      
         ) {
            
      
      
        return
      
      
        ;
        }

        
      
      
        //
      
      
         設(shè)置現(xiàn)在狀態(tài)已完成
      
      
        state = 2
      
        ;

        
      
      
        //
      
      
         清除超時(shí)設(shè)置
      
      
        if
      
      
         ( timeoutTimer ) {
            clearTimeout( timeoutTimer );
        }
        
      
      
        //
      
      
         不管jqXHR對(duì)象要被用到何時(shí),
      
      
        //
      
      
         釋放transport的引用使得他可以先被垃圾回收
      
      
        transport =
      
         undefined;

        
      
      
        //
      
      
         緩存響應(yīng)頭
      
      
        responseHeadersString = headers || ""
      
        ;

        
      
      
        //
      
      
         設(shè)置readyState
      
      
        jqXHR.readyState = status > 0 ? 4 : 0
      
        ;

        
      
      
        //
      
      
         得到響應(yīng)數(shù)據(jù)
      
      
        if
      
      
         ( responses ) {
            
      
      
        //
      
      
         通過(guò)ajaxHandleResponses處理數(shù)據(jù)
      
      
            response =
      
         ajaxHandleResponses( s, jqXHR, responses );
        }

        
      
      
        //
      
      
         If successful, handle type chaining
      
      
        //
      
      
         如果成功
      
      
        if
      
       ( status >= 200 && status < 300 || status === 304
      
         ) {

            
      
      
        //
      
      
         看看是否需要緩存If-Modified-Since和If-None-Match頭
      
      
        if
      
      
         ( s.ifModified ) {
                
      
      
        //
      
      
         取得Last-Modified
      
      
                modified = jqXHR.getResponseHeader("Last-Modified"
      
        );
                
      
      
        //
      
      
         如果Last-Modified存在
      
      
        if
      
      
         ( modified ) {
                    
      
      
        //
      
      
         在jQuery.lastModified[cacheURL]保存Last-Modified
      
      
                    jQuery.lastModified[ cacheURL ] =
      
         modified;
                }
                
      
      
        //
      
      
         取得etag
      
      
                modified = jqXHR.getResponseHeader("etag"
      
        );
                
      
      
        //
      
      
         如果etag存在
      
      
        if
      
      
         ( modified ) {
                    
      
      
        //
      
      
         在jQuery.etag[cacheURL]緩存etag
      
      
                    jQuery.etag[ cacheURL ] =
      
         modified;
                }
            }

            
      
      
        //
      
      
         如果沒(méi)有修改
      
      
        if
      
       ( status === 304
      
         ) {
                
      
      
        //
      
      
         設(shè)置成功
      
      
                isSuccess = 
      
        true
      
      
        ;
                
      
      
        //
      
      
         設(shè)置狀態(tài)為notmodified
      
      
                statusText = "notmodified"
      
        ;

            
      
      
        //
      
      
         否則得到必要的數(shù)據(jù)
      
      
            } 
      
        else
      
      
         {
                isSuccess 
      
      =
      
         ajaxConvert( s, response );
                statusText 
      
      =
      
         isSuccess.state;
                success 
      
      =
      
         isSuccess.data;
                error 
      
      =
      
         isSuccess.error;
                isSuccess 
      
      = !
      
        error;
            }
        
      
      
        //
      
      
         如果失敗
      
      
        } 
      
        else
      
      
         {
            
      
      
        //
      
      
         從statusText獲取error狀態(tài)
      
      
        //
      
      
         在設(shè)置statusText成"error"
      
      
        //
      
      
         并改變status為0
      
      
            error =
      
         statusText;
            
      
      
        if
      
       ( status || !
      
        statusText ) {
                statusText 
      
      = "error"
      
        ;
                
      
      
        if
      
       ( status < 0
      
         ) {
                    status 
      
      = 0
      
        ;
                }
            }
        }

        
      
      
        //
      
      
         開(kāi)始設(shè)置山寨xhr對(duì)象jqXHR的status和statusText
      
      
        jqXHR.status =
      
         status;
        jqXHR.statusText 
      
      = ( nativeStatusText || statusText ) + ""
      
        ;

        
      
      
        //
      
      
         根據(jù)成功還是失敗,對(duì)deferred進(jìn)行回調(diào)
      
      
        if
      
      
         ( isSuccess ) {
            deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );    
        } 
      
      
        else
      
      
         {
            deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
        }

        
      
      
        //
      
      
         根據(jù)目前statusCode回調(diào)
      
      
                jqXHR.statusCode( statusCode );
        statusCode 
      
      =
      
         undefined;

        
      
      
        //
      
      
         如果需要觸發(fā)全局事件
      
      
        if
      
      
         ( fireGlobals ) {
            
      
      
        //
      
      
         對(duì)指定元素觸發(fā)事件ajaxSuccess或者ajaxError
      
      
            globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError"
      
        ,
                [ jqXHR, s, isSuccess 
      
      ?
      
         success : error ] );
        }

        
      
      
        //
      
      
         回調(diào)完成后的Callbacks隊(duì)列
      
      
                completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

        
      
      
        //
      
      
         如果需要觸發(fā)全局事件
      
      
        if
      
      
         ( fireGlobals ) {
            
      
      
        //
      
      
         對(duì)指定元素觸發(fā)事件ajaxComplete
      
      
            globalEventContext.trigger( "ajaxComplete"
      
        , [ jqXHR, s ] );
            
      
      
        //
      
      
         該ajax觸發(fā)完畢,標(biāo)記active減1,如果為0,證明所有ajax結(jié)束
      
      
        if
      
       ( !( --
      
        jQuery.active ) ) {
                
      
      
        //
      
      
         觸發(fā)ajaxStop事件
      
      
                jQuery.event.trigger("ajaxStop"
      
        );
            }
        }
    }

    
      
      
        //
      
      
         返回山寨xhr
      
      
        return
      
      
         jqXHR;
};
      
    

?

?

jQuery ajax —— 主函數(shù)分析


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产亚洲精品97在线观看 | 色插视频 | 午夜深夜福利网址 | 日本道在线视频 | 欧美成人观看视频在线 | 欧美日韩国产一区三区 | 欧美日韩亚 | 久99久爱精品免费观看视频 | 999精品视频这里只有精品 | 22222se男人的天堂 | 青青青爽在线视频观看大全 | 欧美午夜性刺激在线观看免费 | 有色视频在线观看 | 57pao一国产成视频永久免费 | 国产精品久久福利新婚之夜 | 成人欧美一区二区三区在线观看 | 四虎影院2022| 综合色好色 | 美女一级a毛片免费观看 | 日本在线色视频 | 日韩精品欧美亚洲高清有无 | 中文字幕精品一区二区三区在线 | 久热精品视频在线观看 | 日韩精品一区二区三区 在线观看 | 成人精品免费视频 | 国产www在线播放 | 午夜免费 | 有色视频在线观看 | 欧美爱爱爱爱免费视频 | 亚洲国产精品综合久久 | 国产一区二区成人 | 久久综合久久综合久久综合 | 亚洲黄色在线观看视频 | 日韩视频一区二区 | 殴美一级视频 | 久热re国产手机在线观看 | 操人视频网站 | 玖玖精品在线观看 | 波多野结衣xxxx性精品 | 久久国产精品视频一区 | 日韩不卡在线播放 |