先来看一看jQuery的Ajax核心处理流程($.ajax)
第一步,为传递的参数做适配。url可以包含在options中
//传递的参数只是一个对象if ( typeof url === "object" ) { options = url; url = undefined;}//options强制转成对象options = options || {};
第二步,创建一些变量,比较重要的是:创建最终选项对象s、全局事件上下文是callbackContext、创建deferred和completeDeferred、创建jqXHR对象。
var //跨域检测变量 parts, ... //创建最终选项对象 s = jQuery.ajaxSetup( {}, options ), //回调上下文 callbackContext = s.context || s, //全局事件上下文是callbackContext,如果他是一个DOM节点或jQuery集合(对象) globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? jQuery( callbackContext ) : jQuery.event, // Deferreds deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory"), ... jqXHR = { readyState: 0, //建立请求头哈希表 getResponseHeader: function( key ) {...}, // Raw string getAllResponseHeaders: function() {...}, //缓存请求头 setRequestHeader: function( name, value ) {...}, //重写响应content-type头 overrideMimeType: function( type ) {...}, //取决于状态的回调 statusCode: function( map ) {...}, //取消请求 abort: function( statusText ) {...} };//添加延时事件deferred.PRomise( jqXHR ).complete = completeDeferred.add;jqXHR.success = jqXHR.done;jqXHR.error = jqXHR.fail;
第三步,检查是否跨域。其中需要注意的是ajaxLocParts在jQuery初始化的时候就定义了
//rurl = /^([/w.+-]+:)(?:////([^//?#:]*)(?::(/d+)|)|)///需要注意的是本地文件一般形如"file:///C:/Users/Administrator/Desktop/jquery/test.html"//最终结果为["file://", "file:", "", undefined]//正常http请求如"http://www.baidu.com"//的到结果为["http://www.baidu.com", "http:", "www.baidu.com", undefined]//如果是"http://192.168.0.17:8080/baidu/com"//则得到的结果["http://192.168.0.17:8080", "http:", "192.168.0.17", "8080"]ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];//跨域请求是为了当我们有一个协议:host:port不匹配的时候if ( s.crossDomain == null ) { 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转化成一个查询字符串
//processData默认为true//默认情况下,通过data属性传递进来的数据,如果是一个对象(技术上讲,只要不是字符串),//都会处理转化成一个查询字符串,以配合默认内容类型 "application/x-www-form-urlencoded"if ( s.data && s.processData && typeof s.data !== "string" ) { s.data = jQuery.param( s.data, s.traditional );}
第五步,运行prefilters进行预处理
//运行prefiltersinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
预处理和分发器使用的是同一个函数inspectPrefiltersOrTransports,需要注意的是当dataType为jsonp的时候是以dataType为script的方式来处理的
第六步,根据传递的选项设置默认参数处理(主要包括如果type是GET等类型,传递的数据将被附加到URL上;添加请求头如If-Modified-Since/If-None-Match、Content-Type、Accept等;)
…//没有请求内容(type一般为GET的情况)if ( !s.hasContent ) { //如果data可用,添加到url if ( s.data ) { cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); // #9682:删除data保证重试是不会被使用 delete s.data; } //cache默认值:true(dataType为'script'或'jsonp'时,则默认为false)。 //指示是否缓存URL请求。如果设为false将强制浏览器不缓存当前URL请求。 //该参数只对HEAD、GET请求有效(POST请求本身就不会缓存) if ( s.cache === false ) { //rts = /([?&])_=[^&]*/ s.url = rts.test( cacheURL ) ? //如果已经有一个'_'参数,设置他的值 cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) : //否则添加到url后面 //ajax_rquery = //?/ cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++; }}// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.//ifModified默认为false//允许当前请求仅在服务器数据改变时获取新数据(如未更改,浏览器从缓存中获取数据)//它使用HTTP头信息Last-Modified来判断。从jQuery 1.4开始,他也会检查服务器指定的'etag'来确定数据是否已被修改。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 ] ); }}//contentType默认值:'application/x-www-form-urlencoded; charset=UTF-8'。//使用指定的内容编码类型将数据发送给服务器。//W3C的xmlHttpRequest规范规定charset始终是UTF-8,将其改也无法强制浏览器更改字符编码。if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { jqXHR.setRequestHeader( "Content-Type", s.contentType );}//设置Accept头,依赖于dataTypejqXHR.setRequestHeader( "Accept", s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : s.accepts[ "*" ]);// Check for headers option//headers默认值:{}。//以对象形式指定附加的请求头信息。请求头X-Requested-With: xmlhttpRequest将始终被添加,//当然你也可以在此处修改默认的XMLHttpRequest值。//headers中的值可以覆盖beforeSend回调函数中设置的请求头(意即beforeSend先被调用)。for ( i in s.headers ) { jqXHR.setRequestHeader( i, s.headers[ i ] );}…//安装回调到deferreds上for ( i in { success: 1, error: 1, complete: 1 } ) { jqXHR[ i ]( s[ i ] );}
新闻热点
疑难解答