成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

jQuery ajax 源碼分析之預(yù)處理和分發(fā)函數(shù)(prefilter/transport)

he_xd / 2173人閱讀

摘要:調(diào)用的情況下,我們通常用來請求數(shù)據(jù)的方法有前五種方法,在的實現(xiàn)中,本質(zhì)上還是在調(diào)用第六種方法實現(xiàn)的單純在源碼中看前五個函數(shù),代碼量都很少,多一點也就是函數(shù),涉及到了的寫法,在調(diào)用成功時,對返回的數(shù)據(jù)使用內(nèi)部方法進行渲

調(diào)用jQuery 的情況下,我們通常用來請求數(shù)據(jù)的方法有

$(element).load(url, callback)

$.get(url, data, callback, type)

$.post(url, data, callback, type)

$.getJSON(url, data, callback)

$.getScript(url, callback)

$.ajax(options)

前五種方法,在jQuery 的實現(xiàn)中,本質(zhì)上還是在調(diào)用第六種方法實現(xiàn)的

$().load() -> jQuery.fn.load -> $.ajax()
$.get() -> jQuery.each( [ "get", "post" ], function() {}) -> $.ajax()
$.post() -> jQuery.each( [ "get", "post" ], function() {}) -> $.ajax()
$.getJSON -> getJSON() -> $.get() -> $.ajax()
$.getScript -> getScript() -> $.get() -> $.ajax()

單純在源碼中看前五個函數(shù),代碼量都很少,多一點也就是$().load() 函數(shù),涉及到了deferred 的寫法,在調(diào)用成功時,對返回的數(shù)據(jù)使用內(nèi)部方法html() 進行渲染,但是代碼也不難看懂

下面重點介紹$().ajax() 方法,ajax 內(nèi)部結(jié)構(gòu)為

jQuery.extend({ 
    active // 調(diào)用ajax的次數(shù)
    lastModified // 緩存標識
    etag // 緩存標識
    ajaxSettings // 默認參數(shù)設(shè)置
    ajaxSetup // 開發(fā)者自定義參數(shù)與默認參數(shù)復(fù)制到當前ajax的參數(shù)中
    ajaxPrefilter // 觸發(fā)ajax調(diào)用前的預(yù)處理函數(shù)
    ajaxTransport // 觸發(fā)ajax調(diào)用后的處理函數(shù)
    ajax // ajax的主函數(shù)
    getJSON  // getJSON 函數(shù)
    getScript // getScript 函數(shù)
})  

重點需要介紹的函數(shù)有三個ajaxPrefilter,ajaxTransport , ajax

ajaxPrefilter 函數(shù)通過addToPrefiltersOrTransports( prefilters ) 實現(xiàn)的,看下jQuery 通過ajaxPrefilter 做了哪些操作

jQuery.ajaxPrefilter( "script", function( s ) {}) 如果dataTypescript 的話,設(shè)置緩存操作,如果是跨域的話,type 就必須設(shè)置為get

jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {}) 如果dataTypejson jsonp 的話,就需要做進一步的操作了

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

var callbackName, overwritten, responseContainer,
  // 判斷json是在url中還是在form中
  jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
      "url" :
      typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
  );

// Handle iff the expected data type is "jsonp" or we have a parameter to set
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {

  // Get callback name, remembering preexisting value associated with it
  // 如果jsonp的callback是個函數(shù)的話,就執(zhí)行完函數(shù)后返回結(jié)果,如果不是函數(shù),就返回自身
  callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
      s.jsonpCallback() :
      s.jsonpCallback;

  // Insert callback into url or form data
  // 把callback插入到form表單中,如果使用jsonp的話,就把callback放到url的后面
  if ( jsonProp ) {
      s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
  } else if ( s.jsonp !== false ) {
      s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
  }

  // Use data converter to retrieve json after script execution
  // responseContainer為沖送到url的數(shù)據(jù)
  s.converters["script json"] = function() {
      if ( !responseContainer ) {
          jQuery.error( callbackName + " was not called" );
      }
      // 返回 jsonp 的callback的參數(shù)
      return responseContainer[ 0 ];
  };

  // force json dataType
  s.dataTypes[ 0 ] = "json";

  // Install callback
  // responseContainer 拿到 callback 函數(shù)中的參數(shù),就是觸發(fā) callback 函數(shù)的時,傳遞給 callback 的參數(shù)
  // ajax 觸發(fā)成功后,success中的第一個參數(shù)就是 傳遞給 callback 的參數(shù)
  overwritten = window[ callbackName ];
  window[ callbackName ] = function() {
      responseContainer = arguments;
  };

  // Clean-up function (fires after converters)
  jqXHR.always(function() {
      // Restore preexisting value
      window[ callbackName ] = overwritten;

      // Save back as free
      if ( s[ callbackName ] ) {
          // make sure that re-using the options doesn"t screw things around
          s.jsonpCallback = originalSettings.jsonpCallback;

          // save the callback name for future use
          oldCallbacks.push( callbackName );
      }

      // Call if it was a function and we have a response
      // 觸發(fā) callback 函數(shù)
      if ( responseContainer && jQuery.isFunction( overwritten ) ) {
          overwritten( responseContainer[ 0 ] );
      }
      // 清空 callback 函數(shù)
      responseContainer = overwritten = undefined;
  });

  // Delegate to script
  // 注意,這里返回script,表明會使用script的方法處理
  return "script";
}
});

然后再看addToPrefiltersOrTransports() 函數(shù),會根據(jù)每種dataType 存儲對應(yīng)的函數(shù)

// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
// 添加 prefilters(預(yù)處理器)/transports(分發(fā)處理器) 里面的函數(shù)
function addToPrefiltersOrTransports( structure ) {

    // dataTypeExpression is optional and defaults to "*"
    return function( dataTypeExpression, func ) {

        // 這是在操作原生的 Ajax 的時候,沒有傳入 dataTypeExpression
        if ( typeof dataTypeExpression !== "string" ) {
            func = dataTypeExpression;
            dataTypeExpression = "*";
        }

        var dataType,
            i = 0,
            dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];

        if ( jQuery.isFunction( func ) ) {
            // For each dataType in the dataTypeExpression
            while ( (dataType = dataTypes[i++]) ) {
                // Prepend if requested
                // 有+,說明有多個回調(diào),就把回調(diào)往前加
                if ( dataType[0] === "+" ) {
                    dataType = dataType.slice( 1 ) || "*";
                    (structure[ dataType ] = structure[ dataType ] || []).unshift( func );

                // Otherwise append
                // 沒有多個回調(diào),就往后添加
                } else {
                    (structure[ dataType ] = structure[ dataType ] || []).push( func );
                }
            }
        }
    };
}

然后我們再看ajaxTransport 函數(shù),該函數(shù)也是通過addToPrefiltersOrTransports() 函數(shù)來存儲某種dataType 類型對應(yīng)的函數(shù)

// Bind script tag hack transport
// 如果有跨域的話,就會有返回值,沒有跨域的話,就沒有返回值
// 這時候到 inpectPrefiltersOrTransports 函數(shù)中看 return !(selected = dataTypeOrTransport) 中的 dataTypeOrTransport 是有值的
jQuery.ajaxTransport( "script", function( s ) {
    // This transport only deals with cross domain requests
    // 如果需要跨域的情況下
    if ( s.crossDomain ) {
        var script, callback;
        return {
            // send函數(shù)為在請求的url中創(chuàng)建script標簽
            send: function( _, complete ) {
                // 跨域的操作,就是動態(tài)創(chuàng)建script
                script = jQuery("                
閱讀需要支付1元查看
<