摘要:歡迎來我的專欄查看系列文章。主要來看函數(shù)函數(shù)返回值有兩個,其中就是發(fā)送函數(shù)了,一步一步,發(fā)送下來,無需多說明。參考源碼分析系列整體結(jié)構(gòu)源碼分析系列總結(jié)觸碰異步詳解本文在上的源碼地址,歡迎來。
歡迎來我的專欄查看系列文章。
關(guān)于 ajax,東西太多了,我本來想避開 ajax,避而不提,但覺得 ajax 這么多內(nèi)容,不說又少點什么,就簡單點來介紹吧,加上最近準備內(nèi)推面試的時候,看了不少 ajax 的相關(guān)知識。
寫在 jQuery 的 ajax 之前首先,我們還是來了解一下 js 中的 http 請求。http 協(xié)議中有請求體和響應(yīng)體,對于請求的一方,無論是哪一種語言,我比較關(guān)心如下幾個方面:請求的配置參數(shù)包括 url,post/get 等;請求有請求頭,那么請求頭的參數(shù)又該由哪個函數(shù)來設(shè)置;如何判斷請求已經(jīng)成功;響應(yīng)狀態(tài)碼和響應(yīng)數(shù)據(jù)該如何獲得等等。
XMLHttpRequest 對象每天都喊著要寫原生的 js 請求,那么來了,就是這個函數(shù) XMLHttpRequest,它是一套可以在Javascript、VbScript、Jscript等腳本語言中通過http協(xié)議傳送或接收XML及其他數(shù)據(jù)的一套API,萬惡的低版本 IE 有個兼容的 ActiveXObject。
它有兩個版本,第一個版本的功能很少,在不久之后又有了點一個更完善的版本 2.0,功能更全。如果你感興趣,可以來這里看一下XMLHttpRequest。如果你對 http 協(xié)議有著很好的掌握的話,也可以看下面的內(nèi)容。
實現(xiàn)一個簡單的 ajax 請求如果你碰到面試官,讓你手寫一個原生的 ajax 請求,那么下面的東西可能對你非常有幫助:
// 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 對象 var xhr = new XMLHttpRequest(); var url = options.url; xhr.open(options.type, url); // 監(jiān)聽 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; })()
測試在下面:
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 的簡單用法:
通過 new XMLHttpRequest() 建立一個 http 請求對象;
open 函數(shù)的作用是設(shè)置要打開的 url 和類型,建立一個連接,但此時請求并沒有發(fā)送;
setRequestHeader 來設(shè)置請求頭信息;
send 函數(shù)像服務(wù)器發(fā)送數(shù)據(jù)請求;
onreadystatechange 是一個監(jiān)聽函數(shù),當 readyState 改變的時候執(zhí)行,1-2-3-4,4 表示成功返回。xhr.responseText 是返回的響應(yīng)數(shù)據(jù),很明顯,這里是 json 格式,實際要通過響應(yīng)頭來判斷,這里省去了這一步,getAllResponseHeaders 可以獲得所有響應(yīng)頭;
success 函數(shù)和 complete 函數(shù)執(zhí)行的位置和順序問題。
jQuery ajax 的特點通過上面的例子,應(yīng)該可以對 js 的 http 請求有個大致的了解,而 jQuery 的處理則復雜的多,也涉及到和上面功能類似的一些函數(shù),而對于 callback 和 deferred,jQuery 本身就支持:
var deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks( "once memory" );
所以說 jQuery 是一個自給自足的庫,一點也不過分,前面有 Sizzle,整個源碼到處都充滿著 extend 函數(shù),等等。
jQuery.ajaxSetupajaxSetup 是在 ajax 函數(shù)里比較早執(zhí)行的一個函數(shù),這個函數(shù)主要是用來校準參數(shù)用的;
jQuery.extend( { ajaxSetup: function( target, settings ) { return settings ? // 雙層的 ajaxExtend 函數(shù) ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : // Extending ajaxSettings ajaxExtend( jQuery.ajaxSettings, target ); }, } );
ajaxSettings 是一個對象,具體是干什么用的,看看就知道了:
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 原來是一個加強版的 options。
ajaxExtend 是用來將 ajax 函數(shù)參數(shù)進行標準化的,看看哪些參數(shù)沒有賦值,讓它等于默認值,由于 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 中有一個非常重要的對象,jqXHR,它雖然是一個簡稱,但通過縮寫也大致能猜出它是 jquery-XMLHttpRequest。
jqXHR = { readyState: 0, // 0-4 // 熟悉響應(yīng)頭的對這個應(yīng)該不陌生,將響應(yīng)頭數(shù)據(jù)按照 key value 存儲起來 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; }, // 手動設(shè)置請求頭 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 對象了,函數(shù)都進行擴展了。
ajaxTransport那么 XMLHttpRequest 這個函數(shù)到底在哪呢?
jQuery 中有兩個屬性,分別是 ajaxPrefilter 和 ajaxTransport,它們是由 addToPrefiltersOrTransports 函數(shù)構(gòu)造的。主要來看 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ù)返回值有兩個,其中 send 就是發(fā)送函數(shù)了,一步一步,發(fā)送下來,無需多說明。
另外,ajax 對于 jQuery 對象在 ajax 過程提供了很多回調(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,不想去深入研究了,最近暑假實習校招已經(jīng)開始啟動了,暫時先放一放吧,以后有時間再來填坑吧。
參考jQuery源碼分析系列(30) : Ajax 整體結(jié)構(gòu)
jQuery源碼分析系列(37) : Ajax 總結(jié)
觸碰jQuery:AJAX異步詳解
本文在 github 上的源碼地址,歡迎來 star。
歡迎來我的博客交流。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/86825.html
摘要:希望幫助更多的前端愛好者學習。前端開發(fā)者指南作者科迪林黎,由前端大師傾情贊助。翻譯最佳實踐譯者張捷滬江前端開發(fā)工程師當你問起有關(guān)與時,老司機們首先就會告訴你其實是個沒有網(wǎng)絡(luò)請求功能的庫。 前端基礎(chǔ)面試題(JS部分) 前端基礎(chǔ)面試題(JS部分) 學習 React.js 比你想象的要簡單 原文地址:Learning React.js is easier than you think 原文作...
摘要:眼看的源碼就快到頭了,后面還有幾個重要的內(nèi)容,包括和動畫操作,加油把它們看完,百度前端學院的新一批課程也開始了。,當?shù)诙€參數(shù)為的情況,就是,為時,,從源碼來看,就是直接調(diào)用的這兩個函數(shù)。參考源碼分析樣式操作本文在上的源碼地址,歡迎來。 歡迎來我的專欄查看系列文章。 眼看 jQuery 的源碼就快到頭了,后面還有幾個重要的內(nèi)容,包括 ajax 和動畫操作,加油把它們看完,百度前端學院的...
摘要:是什么在介紹的概念之前,我們需要簡單回顧一下前面源碼閱讀系列文章六中講過的和的概念以及它們和語句的關(guān)系。的任務(wù)就是實現(xiàn)請求,執(zhí)行所有涉及到的請求,并依次返回結(jié)果。構(gòu)造出了所有之后,下一步就是執(zhí)行這些了。 上篇文章 中,我們介紹了數(shù)據(jù)讀寫過程中 tikv-client 需要解決的幾個具體問題,本文將繼續(xù)介紹 tikv-client 里的兩個主要的模塊——負責處理分布式計算的 copIte...
閱讀 3532·2021-10-09 09:41
閱讀 2739·2021-10-08 10:18
閱讀 2174·2021-09-10 10:51
閱讀 2674·2021-09-10 10:50
閱讀 771·2021-09-09 09:33
閱讀 3377·2021-09-06 15:14
閱讀 3011·2019-08-30 11:06
閱讀 3241·2019-08-29 14:04