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

資訊專欄INFORMATION COLUMN

jQuery 源碼系列(十九)ajax 的相關(guān)操作

Dean / 1271人閱讀

摘要:歡迎來(lái)我的專欄查看系列文章。主要來(lái)看函數(shù)函數(shù)返回值有兩個(gè),其中就是發(fā)送函數(shù)了,一步一步,發(fā)送下來(lái),無(wú)需多說(shuō)明。參考源碼分析系列整體結(jié)構(gòu)源碼分析系列總結(jié)觸碰異步詳解本文在上的源碼地址,歡迎來(lái)。

歡迎來(lái)我的專欄查看系列文章。

關(guān)于 ajax,東西太多了,我本來(lái)想避開(kāi) ajax,避而不提,但覺(jué)得 ajax 這么多內(nèi)容,不說(shuō)又少點(diǎn)什么,就簡(jiǎn)單點(diǎn)來(lái)介紹吧,加上最近準(zhǔn)備內(nèi)推面試的時(shí)候,看了不少 ajax 的相關(guān)知識(shí)。

寫(xiě)在 jQuery 的 ajax 之前

首先,我們還是來(lái)了解一下 js 中的 http 請(qǐng)求。http 協(xié)議中有請(qǐng)求體和響應(yīng)體,對(duì)于請(qǐng)求的一方,無(wú)論是哪一種語(yǔ)言,我比較關(guān)心如下幾個(gè)方面:請(qǐng)求的配置參數(shù)包括 url,post/get 等;請(qǐng)求有請(qǐng)求頭,那么請(qǐng)求頭的參數(shù)又該由哪個(gè)函數(shù)來(lái)設(shè)置;如何判斷請(qǐng)求已經(jīng)成功;響應(yīng)狀態(tài)碼和響應(yīng)數(shù)據(jù)該如何獲得等等。

XMLHttpRequest 對(duì)象

每天都喊著要寫(xiě)原生的 js 請(qǐng)求,那么來(lái)了,就是這個(gè)函數(shù) XMLHttpRequest,它是一套可以在Javascript、VbScript、Jscript等腳本語(yǔ)言中通過(guò)http協(xié)議傳送或接收XML及其他數(shù)據(jù)的一套API,萬(wàn)惡的低版本 IE 有個(gè)兼容的 ActiveXObject。

它有兩個(gè)版本,第一個(gè)版本的功能很少,在不久之后又有了點(diǎn)一個(gè)更完善的版本 2.0,功能更全。如果你感興趣,可以來(lái)這里看一下XMLHttpRequest。如果你對(duì) http 協(xié)議有著很好的掌握的話,也可以看下面的內(nèi)容。

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 ajax 請(qǐng)求

如果你碰到面試官,讓你手寫(xiě)一個(gè)原生的 ajax 請(qǐng)求,那么下面的東西可能對(duì)你非常有幫助:

// myAjax
var myAjax = (function(){
  var defaultOption = {
    url: false,
    type: "GET",
    data: null,
    success: false,
    complete: false
  }

  var ajax = function(options){
    for(var i in defaultOption){
      options[i] = options[i] || defaultOption[i];
    }
    // http 對(duì)象
    var xhr = new XMLHttpRequest();
    var url = options.url;
    xhr.open(options.type, url);
    // 監(jiān)聽(tīng)
    xhr.onreadystatechange = function(){
      if(xhr.readyState == 4){
        var result, status = xhr.status;
        if(status >= 200 && status < 300 || status == 304){
          result = xhr.responseText;
          if(window.JSON){
            result = JSON.parse(result);
          }else{
            result = eval("(" + result + ")");
          }
          ajaxSuccess(result)
        }
      }
    }
    // post
    if(options.type.toLowerCase() === "post"){
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencode");
    }
    xhr.send(options.data);

    function ajaxSuccess(data){
      var status = "success";
      options.success && options.success(data, options, status, xhr);
      options.complete && options.complete(status);
    }
  }
  // 閉包返回
  return ajax;
})()

測(cè)試在下面:

var success = function(data){
  console.log(data["blog"])
}
var complete = function(status){
  if(status == "success"){
    console.log("success")
  }else{
    console.log("failed")
  }
}
myAjax( {
  url: "https://api.github.com/users/songjinzhong",
  success: success,
  complete: complete
} );

可以得到 XMLHttpRequest 的簡(jiǎn)單用法:

通過(guò) new XMLHttpRequest() 建立一個(gè) http 請(qǐng)求對(duì)象;

open 函數(shù)的作用是設(shè)置要打開(kāi)的 url 和類型,建立一個(gè)連接,但此時(shí)請(qǐng)求并沒(méi)有發(fā)送;

setRequestHeader 來(lái)設(shè)置請(qǐng)求頭信息;

send 函數(shù)像服務(wù)器發(fā)送數(shù)據(jù)請(qǐng)求;

onreadystatechange 是一個(gè)監(jiān)聽(tīng)函數(shù),當(dāng) readyState 改變的時(shí)候執(zhí)行,1-2-3-4,4 表示成功返回。xhr.responseText 是返回的響應(yīng)數(shù)據(jù),很明顯,這里是 json 格式,實(shí)際要通過(guò)響應(yīng)頭來(lái)判斷,這里省去了這一步,getAllResponseHeaders 可以獲得所有響應(yīng)頭;

success 函數(shù)和 complete 函數(shù)執(zhí)行的位置和順序問(wèn)題。

jQuery ajax 的特點(diǎn)

通過(guò)上面的例子,應(yīng)該可以對(duì) js 的 http 請(qǐng)求有個(gè)大致的了解,而 jQuery 的處理則復(fù)雜的多,也涉及到和上面功能類似的一些函數(shù),而對(duì)于 callback 和 deferred,jQuery 本身就支持:

var deferred = jQuery.Deferred(),
  completeDeferred = jQuery.Callbacks( "once memory" );

所以說(shuō) jQuery 是一個(gè)自給自足的庫(kù),一點(diǎn)也不過(guò)分,前面有 Sizzle,整個(gè)源碼到處都充滿著 extend 函數(shù),等等。

jQuery.ajaxSetup

ajaxSetup 是在 ajax 函數(shù)里比較早執(zhí)行的一個(gè)函數(shù),這個(gè)函數(shù)主要是用來(lái)校準(zhǔn)參數(shù)用的;

jQuery.extend( {
  ajaxSetup: function( target, settings ) {
    return settings ?

      // 雙層的 ajaxExtend 函數(shù)
      ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :

      // Extending ajaxSettings
      ajaxExtend( jQuery.ajaxSettings, target );
  },
} );

ajaxSettings 是一個(gè)對(duì)象,具體是干什么用的,看看就知道了:

jQuery.ajaxSettings = {
  url: location.href,
  type: "GET",
  isLocal: rlocalProtocol.test( location.protocol ),
  global: true,
  processData: true,
  async: true,
  contentType: "application/x-www-form-urlencoded; charset=UTF-8",

  accepts: {
    "*": allTypes,
    text: "text/plain",
    html: "text/html",
    xml: "application/xml, text/xml",
    json: "application/json, text/javascript"
  },

  contents: {
    xml: /xml/,
    html: /html/,
    json: /json/
  },

  responseFields: {
    xml: "responseXML",
    text: "responseText",
    json: "responseJSON"
  },

  // Data converters
  // Keys separate source (or catchall "*") and destination types with a single space
  converters: {

    // Convert anything to text
    "* text": String,

    // Text to html (true = no transformation)
    "text html": true,

    // Evaluate text as a json expression
    "text json": JSON.parse,

    // Parse text as xml
    "text xml": jQuery.parseXML
  },

  // For options that shouldn"t be deep extended:
  // you can add your own custom options here if
  // and when you create one that shouldn"t be
  // deep extended (see ajaxExtend)
  flatOptions: {
    url: true,
    context: true
  }
}

ajaxSettings 原來(lái)是一個(gè)加強(qiáng)版的 options。

ajaxExtend 是用來(lái)將 ajax 函數(shù)參數(shù)進(jìn)行標(biāo)準(zhǔn)化的,看看哪些參數(shù)沒(méi)有賦值,讓它等于默認(rèn)值,由于 ajaxExtend 是雙層的,具體要調(diào)試了才能更明白。

function ajaxExtend( target, src ) {
  var key, deep,
    flatOptions = jQuery.ajaxSettings.flatOptions || {};

  for ( key in src ) {
    if ( src[ key ] !== undefined ) {
      ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
    }
  }
  if ( deep ) {
    jQuery.extend( true, target, deep );
  }

  return target;
}
ajax.jqXHR

在 ajax 中有一個(gè)非常重要的對(duì)象,jqXHR,它雖然是一個(gè)簡(jiǎn)稱,但通過(guò)縮寫(xiě)也大致能猜出它是 jquery-XMLHttpRequest。

jqXHR = {
  readyState: 0, // 0-4

  // 熟悉響應(yīng)頭的對(duì)這個(gè)應(yīng)該不陌生,將響應(yīng)頭數(shù)據(jù)按照 key value 存儲(chǔ)起來(lái)
  getResponseHeader: function( key ) {
    var match;
    if ( completed ) {
      if ( !responseHeaders ) {
        responseHeaders = {};
        while ( ( match = /^(.*?):[ 	]*([^
]*)$/mg.exec( responseHeadersString ) ) ) {
          responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
        }
      }
      match = responseHeaders[ key.toLowerCase() ];
    }
    return match == null ? null : match;
  },

  // Raw string
  getAllResponseHeaders: function() {
    return completed ? responseHeadersString : null;
  },

  // 手動(dòng)設(shè)置請(qǐng)求頭
  setRequestHeader: function( name, value ) {
    if ( completed == null ) {
      name = requestHeadersNames[ name.toLowerCase() ] =
        requestHeadersNames[ name.toLowerCase() ] || name;
      requestHeaders[ name ] = value;
    }
    return this;
  },

  // Overrides response content-type header
  overrideMimeType: function( type ) {
    if ( completed == null ) {
      s.mimeType = type;
    }
    return this;
  },

  // Status-dependent callbacks
  statusCode: function( map ) {
    var code;
    if ( map ) {
      if ( completed ) {

        // Execute the appropriate callbacks
        jqXHR.always( map[ jqXHR.status ] );
      } else {

        // Lazy-add the new callbacks in a way that preserves old ones
        for ( code in map ) {
          statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
        }
      }
    }
    return this;
  },

  // Cancel the request
  abort: function( statusText ) {
    var finalText = statusText || strAbort;
    if ( transport ) {
      transport.abort( finalText );
    }
    done( 0, finalText );
    return this;
  }
};

jqXHR 已經(jīng)完全可以取代 XHR 對(duì)象了,函數(shù)都進(jìn)行擴(kuò)展了。

ajaxTransport

那么 XMLHttpRequest 這個(gè)函數(shù)到底在哪呢?

jQuery 中有兩個(gè)屬性,分別是 ajaxPrefilterajaxTransport,它們是由 addToPrefiltersOrTransports 函數(shù)構(gòu)造的。主要來(lái)看 ajaxTransport 函數(shù):

jQuery.ajaxTransport( function( options ) {
  var callback, errorCallback;

  // Cross domain only allowed if supported through XMLHttpRequest
  if ( support.cors || xhrSupported && !options.crossDomain ) {
    return {
      send: function( headers, complete ) {
        var i,
          xhr = options.xhr();// xhr() = XMLHttpRequest()
        xhr.open(
          options.type,
          options.url,
          options.async,
          options.username,
          options.password
        );

        // Apply custom fields if provided
        if ( options.xhrFields ) {
          for ( i in options.xhrFields ) {
            xhr[ i ] = options.xhrFields[ i ];
          }
        }

        // Override mime type if needed
        if ( options.mimeType && xhr.overrideMimeType ) {
          xhr.overrideMimeType( options.mimeType );
        }

        // X-Requested-With header
        // For cross-domain requests, seeing as conditions for a preflight are
        // akin to a jigsaw puzzle, we simply never set it to be sure.
        // (it can always be set on a per-request basis or even using ajaxSetup)
        // For same-domain requests, won"t change header if already provided.
        if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
          headers[ "X-Requested-With" ] = "XMLHttpRequest";
        }

        // Set headers
        for ( i in headers ) {
          xhr.setRequestHeader( i, headers[ i ] );
        }

        // Callback
        callback = function( type ) {
          return function() {
            if ( callback ) {
              callback = errorCallback = xhr.onload =
                xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;

              if ( type === "abort" ) {
                xhr.abort();
              } else if ( type === "error" ) {

                // Support: IE <=9 only
                // On a manual native abort, IE9 throws
                // errors on any property access that is not readyState
                if ( typeof xhr.status !== "number" ) {
                  complete( 0, "error" );
                } else {
                  complete(

                    // File: protocol always yields status 0; see #8605, #14207
                    xhr.status,
                    xhr.statusText
                  );
                }
              } else {
                complete(
                  xhrSuccessStatus[ xhr.status ] || xhr.status,
                  xhr.statusText,

                  // Support: IE <=9 only
                  // IE9 has no XHR2 but throws on binary (trac-11426)
                  // For XHR2 non-text, let the caller handle it (gh-2498)
                  ( xhr.responseType || "text" ) !== "text"  ||
                  typeof xhr.responseText !== "string" ?
                    { binary: xhr.response } :
                    { text: xhr.responseText },
                  xhr.getAllResponseHeaders()
                );
              }
            }
          };
        };

        // Listen to events
        xhr.onload = callback();
        errorCallback = xhr.onerror = callback( "error" );

        // Support: IE 9 only
        // Use onreadystatechange to replace onabort
        // to handle uncaught aborts
        if ( xhr.onabort !== undefined ) {
          xhr.onabort = errorCallback;
        } else {
          xhr.onreadystatechange = function() {

            // Check readyState before timeout as it changes
            if ( xhr.readyState === 4 ) {

              // Allow onerror to be called first,
              // but that will not handle a native abort
              // Also, save errorCallback to a variable
              // as xhr.onerror cannot be accessed
              window.setTimeout( function() {
                if ( callback ) {
                  errorCallback();
                }
              } );
            }
          };
        }

        // Create the abort callback
        callback = callback( "abort" );

        try {

          // Do send the request (this may raise an exception)
          xhr.send( options.hasContent && options.data || null );
        } catch ( e ) {

          // #14683: Only rethrow if this hasn"t been notified as an error yet
          if ( callback ) {
            throw e;
          }
        }
      },

      abort: function() {
        if ( callback ) {
          callback();
        }
      }
    };
  }
} );

ajaxTransport 函數(shù)返回值有兩個(gè),其中 send 就是發(fā)送函數(shù)了,一步一步,發(fā)送下來(lái),無(wú)需多說(shuō)明。

另外,ajax 對(duì)于 jQuery 對(duì)象在 ajax 過(guò)程提供了很多回調(diào)函數(shù):

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

jQuery.event.trigger( "ajaxStart" );
...
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
...
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",[ jqXHR, s, isSuccess ? success : error ] );
...
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
...
jQuery.event.trigger( "ajaxStop" );

ajax 東西太多了,至少有 1000 行的代碼吧。

總結(jié)

關(guān)于 ajax,不想去深入研究了,最近暑假實(shí)習(xí)校招已經(jīng)開(kāi)始啟動(dòng)了,暫時(shí)先放一放吧,以后有時(shí)間再來(lái)填坑吧。

參考

jQuery源碼分析系列(30) : Ajax 整體結(jié)構(gòu)
jQuery源碼分析系列(37) : Ajax 總結(jié)
觸碰jQuery:AJAX異步詳解

本文在 github 上的源碼地址,歡迎來(lái) star。

歡迎來(lái)我的博客交流。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86825.html

相關(guān)文章

  • 前端相關(guān)大雜燴

    摘要:希望幫助更多的前端愛(ài)好者學(xué)習(xí)。前端開(kāi)發(fā)者指南作者科迪林黎,由前端大師傾情贊助。翻譯最佳實(shí)踐譯者張捷滬江前端開(kāi)發(fā)工程師當(dāng)你問(wèn)起有關(guān)與時(shí),老司機(jī)們首先就會(huì)告訴你其實(shí)是個(gè)沒(méi)有網(wǎng)絡(luò)請(qǐng)求功能的庫(kù)。 前端基礎(chǔ)面試題(JS部分) 前端基礎(chǔ)面試題(JS部分) 學(xué)習(xí) React.js 比你想象的要簡(jiǎn)單 原文地址:Learning React.js is easier than you think 原文作...

    fuyi501 評(píng)論0 收藏0
  • jQuery 源碼系列(十八)class 相關(guān)操作

    摘要:眼看的源碼就快到頭了,后面還有幾個(gè)重要的內(nèi)容,包括和動(dòng)畫(huà)操作,加油把它們看完,百度前端學(xué)院的新一批課程也開(kāi)始了。,當(dāng)?shù)诙€(gè)參數(shù)為的情況,就是,為時(shí),,從源碼來(lái)看,就是直接調(diào)用的這兩個(gè)函數(shù)。參考源碼分析樣式操作本文在上的源碼地址,歡迎來(lái)。 歡迎來(lái)我的專欄查看系列文章。 眼看 jQuery 的源碼就快到頭了,后面還有幾個(gè)重要的內(nèi)容,包括 ajax 和動(dòng)畫(huà)操作,加油把它們看完,百度前端學(xué)院的...

    BingqiChen 評(píng)論0 收藏0
  • TiDB 源碼閱讀系列文章(十九)tikv-client(下)

    摘要:是什么在介紹的概念之前,我們需要簡(jiǎn)單回顧一下前面源碼閱讀系列文章六中講過(guò)的和的概念以及它們和語(yǔ)句的關(guān)系。的任務(wù)就是實(shí)現(xiàn)請(qǐng)求,執(zhí)行所有涉及到的請(qǐng)求,并依次返回結(jié)果。構(gòu)造出了所有之后,下一步就是執(zhí)行這些了。 上篇文章 中,我們介紹了數(shù)據(jù)讀寫(xiě)過(guò)程中 tikv-client 需要解決的幾個(gè)具體問(wèn)題,本文將繼續(xù)介紹 tikv-client 里的兩個(gè)主要的模塊——負(fù)責(zé)處理分布式計(jì)算的 copIte...

    whataa 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<