欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

jQuery ajax —— 主函數分析

系統 2232 0

由于jQuery ajax對Callbacks、Deferred、serialize、event等模塊的依賴,建議對這些模塊沒有認識的朋友看一下 jQuery Callbacks jQuery Deferred jQuery serialize jQuery event(上) jQuery event(下)

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

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

?

可鏈式操作

既然是jQuery必然先要解決的是鏈式操作的問題。

jQuery中的Deferred可以實現異步鏈式模型實現,Promise對象可以輕易的綁定成功、失敗、進行中三種狀態的回調函數,然后通過在狀態碼在來回調不同的函數就行了。

?

但僅僅返回一個promise沒什么用

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

jqXHR就是這樣的東西,實際上他是一個山寨版的XHR對象。

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

      
        //
      
      
         贗品xhr,或者說山寨xhr……╮(╯▽╰)╭
      
      
        
//
      
      
         為了能夠實現鏈式操作
      
      
        
//
      
      
         順便擴展一下xhr對象功能
      
      
        
//
      
      
         還有提供一定的容錯處理
      
      
jqXHR =
      
         {
    
      
      
        //
      
      
         準備狀態
      
      
    readyState: 0
      
        ,

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

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

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

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

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

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

?

可是這還沒有鏈式啊!

怎么把jqXHR變成一個Promise呢?

讓一個對象擁有另一個對象的方法,大家會想到什么呢?

繼承?

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

應該說動態、弱類的特點。

什么意思?就是將Promise上的方法插到jqXHR對象上就行了。

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

這樣子直接插上去在強類語言中是做不到的,當然也可以用組合模式來實現一個對象擁有多個對象的方法,但是卻無法動態的去給對象添加各種方法。

強類語言會限制對象一輩子只能“會”那么幾種“方法”,Javascript的對象可以在生命周期內隨意“學習”各種“方法”。

所以說,強類語言和Javascript的對象模型是有差別的,將設計模式生搬硬套進Javascript或許是錯誤的。

我們再舉個例子,比如如果用所謂的Javascript組合模式來重寫上面的代碼可能會是這樣的:

        
          //
        
        
           定義局部變量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();
      

大家覺得哪個好呢?

變成上面的樣子主要是因為要解決下面兩個問題:

  1. jqXHR由于是暴露在外的,他不能包含deferred和completeDeferred,不允許用戶在外部操作這兩個對象的狀態。
  2. deferred和completeDeferred也不能成為jqXHR的私有變量,因為還要更具ajax事件觸發。

?

提供全局事件,使得UI可以根據ajax狀態進行改變

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

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

當ajax開始時模擬全局事件,ajaxStart。

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

ajax發送消息,觸發ajaxSend。

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

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

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

結束時候觸發ajaxSuccess或ajaxError,再出發ajaxComplete,如果全部ajax結束則觸發ajaxStop。

?

?

是否允許使用緩存數據

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

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

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

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

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

通過給地址附加參數_=xxx來避免緩存。

      
        //
      
      
         看看需不需要設置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 ] );
        }
    }
      
    

以及設置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頭信息。

?

設置超時

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

主要功能分析完了,完整備注代碼見下。?

?

完整備注

      jQuery.ajax = 
      
        function
      
      
        ( url, options ) {

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

    
      
      
        //
      
      
         設置options
      
      
    options = options ||
      
         {};

    
      
      
        var
      
      
         transport,
        
      
      
        //
      
      
         緩存cacheURL
      
      
                cacheURL,
        
      
      
        //
      
      
         響應頭
      
      
                responseHeadersString,
        responseHeaders,
        
      
      
        //
      
      
         超時控制器
      
      
                timeoutTimer,
        
      
      
        //
      
      
         跨域判定變量
      
      
                parts,
        
      
      
        //
      
      
         是否需要觸發全局事件
      
      
                fireGlobals,
        
      
      
        //
      
      
         循環變量
      
      
                i,
        
      
      
        //
      
      
         通過jQuery.ajaxSetup改造參數對象
      
      
        s =
      
         jQuery.ajaxSetup( {}, options ),
        
      
      
        //
      
      
         回調指定上下文,也就是他的this
      
      
        callbackContext = s.context ||
      
         s,
        
      
      
        //
      
      
         全局事件中的相應函數的指定上下文
      
      
        //
      
      
         有s.context,且是DOM節點,或者jQuery收集器
      
      
        globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
            
      
        //
      
      
         通過jQuery包裝
      
      
                    jQuery( callbackContext ) :
            
      
      
        //
      
      
         否則為jQuery.event
      
      
                    jQuery.event,
        
      
      
        //
      
      
         新建一個deferred
      
      
        deferred =
      
         jQuery.Deferred(),
        
      
      
        //
      
      
         deferred完成后的Callbacks隊列
      
      
        completeDeferred = jQuery.Callbacks("once memory"
      
        ),
        
      
      
        //
      
      
         對應狀態的回調函數集
      
      
        statusCode = s.statusCode ||
      
         {},
        
      
      
        //
      
      
         請求頭
      
      
        requestHeaders =
      
         {},
        requestHeadersNames 
      
      =
      
         {},
        
      
      
        //
      
      
         包裝類jqXHR的狀態
      
      
        state = 0
      
        ,
        
      
      
        //
      
      
         默認中斷消息
      
      
        strAbort = "canceled"
      
        ,
        
      
      
        //
      
      
         贗品xhr,或者說山寨xhr……╮(╯▽╰)╭
      
      
        //
      
      
         為了能夠實現鏈式操作
      
      
        //
      
      
         順便擴展一下xhr對象功能
      
      
        //
      
      
         還有提供一定的容錯處理
      
      
        jqXHR =
      
         {
            
      
      
        //
      
      
         準備狀態
      
      
            readyState: 0
      
        ,

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

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

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

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

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

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

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

    
      
      
        //
      
      
         確定url參數,否則用當前地址。將地址的#號后面的所有東西去掉
      
      
        //
      
      
         比如http://127.0.0.1#main,去掉這個#main
      
      
        //
      
      
         如果開頭是//,及數據傳輸協議沒有,那么用當前頁面的數據傳輸協議替換
      
      
        //
      
      
         比如//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;

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

    
      
      
        //
      
      
         當協議、主機、端口和當前不匹配時,證明這是一個跨域請求
      
      
        if
      
       ( s.crossDomain == 
      
        null
      
      
         ) {
        
      
      
        //
      
      
         分隔當前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已經是一個字符串了,那么就不用轉換了
      
      
        if
      
       ( s.data && s.processData && 
      
        typeof
      
       s.data !== "string"
      
         ) {
        
      
      
        //
      
      
         序列化
      
      
        s.data =
      
         jQuery.param( s.data, s.traditional );
    }

    
      
      
        //
      
      
         預過濾
      
      
            inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

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

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

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

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

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

    
      
      
        //
      
      
         緩存URL,用來在之后設置If-Modified-Since和If-None-Match
      
      
    cacheURL =
      
         s.url;

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

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

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

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

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

    
      
      
        //
      
      
         看看需不需要設置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 ] );
        }
    }

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

    
      
      
        //
      
      
         根據dataType,設置一個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,將其內參數設置入請求頭
      
      
        for
      
       ( i 
      
        in
      
      
         s.headers ) {
        jqXHR.setRequestHeader( i, s.headers[ i ] );
    }

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

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

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

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

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

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

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

        
      
      
        //
      
      
         如果已經調用過該函數,直接退出
      
      
        if
      
       ( state === 2
      
         ) {
            
      
      
        return
      
      
        ;
        }

        
      
      
        //
      
      
         設置現在狀態已完成
      
      
        state = 2
      
        ;

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

        
      
      
        //
      
      
         緩存響應頭
      
      
        responseHeadersString = headers || ""
      
        ;

        
      
      
        //
      
      
         設置readyState
      
      
        jqXHR.readyState = status > 0 ? 4 : 0
      
        ;

        
      
      
        //
      
      
         得到響應數據
      
      
        if
      
      
         ( responses ) {
            
      
      
        //
      
      
         通過ajaxHandleResponses處理數據
      
      
            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;
                }
            }

            
      
      
        //
      
      
         如果沒有修改
      
      
        if
      
       ( status === 304
      
         ) {
                
      
      
        //
      
      
         設置成功
      
      
                isSuccess = 
      
        true
      
      
        ;
                
      
      
        //
      
      
         設置狀態為notmodified
      
      
                statusText = "notmodified"
      
        ;

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

        
      
      
        //
      
      
         開始設置山寨xhr對象jqXHR的status和statusText
      
      
        jqXHR.status =
      
         status;
        jqXHR.statusText 
      
      = ( nativeStatusText || statusText ) + ""
      
        ;

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

        
      
      
        //
      
      
         根據目前statusCode回調
      
      
                jqXHR.statusCode( statusCode );
        statusCode 
      
      =
      
         undefined;

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

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

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

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

?

?

jQuery ajax —— 主函數分析


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久草免费在线视频 | 理论片91 | 欧美性免费视频 | 日韩女同一区二区三区 | 521国产精品视频 | 一区二区三区国产在线 | 视频一区 精品自拍 | 亚洲国产中文字幕 | 97se亚洲综合在线韩国专区福利 | 亚洲一区二区免费视频 | 999毛片免费观看 | 韩漫重考生漫画画免费读漫画下拉式土豪漫 | 免费在线观看的毛片 | av在线看网站 | а√天堂资源中文最新版地址 | 偿还的影视高清在线观看 | 免费一级做a爰片性视频 | 久久se精品一区二区国产 | 俄罗斯18videosex性 | 精品AV综合一区二区三区 | 精品毛片 | 亚洲不卡视频 | 欧美高清另类自拍视频在线看 | 国产网曝在线观看视频 | 亚欧美 | 国产高清一国产免费软件 | 久久精品二区亚洲w码 | 欧美成人精品一区二区男人看 | 深夜福利影院 | 午夜影院在线免费观看视频 | 超碰97青青草 | 亚洲欧美综合日韩字幕v在线 | 午夜精品久久久久久91 | 欧美黄视频网站 | 久草视频手机在线观看 | 亚洲成a人在线观看 | 日韩欧美第一页 | 亚洲午夜精品一区二区 | 日韩看片 | 猫咪人成免费网站在线观看 | 天天操妹子 |