jQuery-1.9.1源碼分析系列(十六)ajax——ajax框架


  ajax的介紹就不多說了,點擊可看.

  既然是ajax框架,那么閑談一談jQuery的ajax處理思路。

  現在的瀏覽器都支持ajax,只不過不同的瀏覽器使用方法可能有不同(IE使用new window.ActiveXObject("Microsoft.XMLHTTP"),標准瀏覽器使用new window.XMLHttpRequest())。如果按照這種思路,貌似jQajax只需要做好兼容處理就行了?

  不是的,原生的ajax有一個說大不大說小不小的缺點——不支持跨域(同源策略由來已久,自行百度)。所以jQajax添加了這方面的處理,jQajax是如何解決跨域問題的?

  <img src="http://img2.imgtn.bdimg.com/it/u=2406301718,2822592556&fm=21&gp=0.jpg"/>

  是能取到圖片的,很明顯圖片的路徑和你的服務端不是一個域的。你可以試試看所有的帶有src屬性的標簽都不受同源策略的影響。所以,jQuery就使用了這個屬性,對於跨域請求使用script標簽的src來請求路徑

  然后jQuery在加上對ajax事件的三種監聽方式:

  1.全局事件:$(document).on(‘ajaxStart’,func);

  2.ajax設置回調項:$.ajax({url: "php.html", complete: func });

  3.deferred綁定方式:$.ajax(…).done(func);

  基本上這就是jQajax所做的事情。

 

  在正真進入ajax框架核心之前,先來分析一jQuery准備的幾個序列化提交表單的函數。

a. 表單序列化


  所謂的表單序列化即將表單需要提交的內容組成類似:“key=value&key=value…”形式的字符串。

  序列化用到三個函數:

  jQuery.fn. serialize()(序列化函數,篩選出表單中需要提交的數據並以序列化字符串方式返回,形如:“key=value&key=value…”)

  jQuery.fn. serializeArray()(篩選出表單中需要提交的數據並以key/value鍵值對的對象數組格式返回,返回[{name:’key’,value:’select1’},{name:’selectM’,value:’selectM1’}, {name:’selectM’,value:’selectM2’}, { name:’key2’,value:0}…])

  jQuery.param(serializeArray, traditional )(將key/value鍵值對的對象數組序列化為“key=value&key=value…”字符串)。

  

  serialize直接調用jQuery.param( this.serializeArray() )即可。

  serializeArray的源碼如下主要進行三個步驟:提取表單元素、過濾出滿足提交條件的表單元素、組合成key/value鍵值對的對象數組

serializeArray: function() {
    //將form中的表單相關的元素取出來組成數組
    return this.map(function(){
        //表單節點有elements這個特征
        var elements = jQuery.prop( this, "elements" );
        return elements ? jQuery.makeArray( elements ) : this;
    })
    //過濾出為需要提交的表單元素(有name名稱、非disabled元素、非提交按鈕等元素、checkbox/radio的checked的元素)
    .filter(function(){
        var type = this.type;
        //使用.is(":disabled")過濾掉不可用的表單元素
        return this.name && !jQuery( this ).is( ":disabled" ) &&
        rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
        ( this.checked || !manipulation_rcheckableType.test( type ) );
    })
    //將表單提交元素組成name和value的對象數組
    .map(function( i, elem ){
        var val = jQuery( this ).val();

        return val == null ?
        null :
        jQuery.isArray( val ) ?
        jQuery.map( val, function( val ){
            return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
        }) :
        { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
    }).get();
}

  需要注意的是jQuery的過濾結果符合正常的表單提交結果://過濾出為需要提交的表單元素(有name名稱、非disabled元素、非提交按鈕等元素、checkbox/radio的checked的元素)

 

  param函數源碼如下:主要進行兩個處理:將key/value成作為URI組件編碼(保證key和value不會出現特殊符號,即保證了“=”分割的正確性)、使用“&”鏈接並將空白符被替換成了"+"

jQuery.param = function( a, traditional ) {
    var prefix,
    s = [],
    add = function( key, value ) {
            //如果value是函數,執行他得到真正的value
            value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
            //把key和value作為URI組件編碼,保證key和value不會出現特殊符號,即保證了“=”分割的正確性
            s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
        };

    ...

    //傳入的是數組,假設他是一個form表單鍵值對數組
    if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
        //序列化表單元素
        jQuery.each( a, function() {
            add( this.name, this.value );
        });

    } else {
        ...
    }

    //返回序列化結果,注意:空白符被替換成了"+"
    return s.join( "&" ).replace( r20, "+" );
};

  其中encodeURIComponent詳細點擊查看

 

b. ajax的事件監聽


  給ajax綁定事件有三種方式

  1.全局事件:$(document).on(‘ajaxStart’,func);

  2.ajax設置回調項:$.ajax({url: "php.html", complete: func });

  3.deferred綁定方式:$.ajax(…).done(func);

  接下來我們一一講解他們的實現。

 

全局事件(ajaxStart/ajaxStop/ajaxComplete/ajaxError/ajaxSuccess/ajaxSend)

  使用.on事件綁定這種通用方式我們毫無疑問是可以綁定ajax監聽事件,除此之外還可以直接使用$(…).ajaxStart(func)來綁定事件。他們的實現也是用.on來綁定。

jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
        jQuery.fn[ type ] = function( fn ){
            return this.on( type, fn );
        };
});

  觸發事件比較簡單,在進行ajax處理過程中在合適的時機直接使用jQuery.event.trigger直接觸發。以ajaxStart為例

            //如果此時沒有正在執行的請求,則觸發ajaxStart事件
            if ( fireGlobals && jQuery.active++ === 0 ) {
                jQuery.event.trigger("ajaxStart");
            }

  

ajax設置回調項(beforeSend/complete/success/error)

  觸發設置回調項分兩種:beforeSend直接在適當的時機調用。源碼

//調用beforeSend回調,如果回調返回失敗或abort則返回中止
if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
                //中止如果沒有准備好
                return jqXHR.abort();
            }

  complete/success/error則利用Deferred的特性將回調添加到延時隊列,等待延時狀態處理。源碼

//創建最終選項對象
s = jQuery.ajaxSetup( {}, options )
...
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks("once memory"),
...

//添加延時事件
deferred.promise( jqXHR ).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;

//安裝回調到deferreds上
for ( i in { success: 1, error: 1, complete: 1 } ) {
jqXHR[ i ]( s[ i ] );
}

//在ajax請求完成的處理函數中執行completeDeferred的延時列表
function done(){
...
//執行Complete處理
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
...
}

 

deferred方式綁定回調

  Deferred方式綁定事件就不用特別說明了,因為ajax本身就是一個延時對象。直接使用$.ajax(…).done(fn).fail(fn). progress(fn).always(fn).then(fn)。源碼

deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks("once memory"),
...
deferred.promise( jqXHR ).complete = completeDeferred.add;
...
return jqXHR;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM