jQuery-AJAX模块解析-request部分
2015-05-12 14:34
483 查看
说好的讲解ajax模块来着的,讲好的事我从来不骗人~(虽然拖了比较久,不过这是迟来的爱
)
首先来看下传统的Ajax请求代码:
Ajax请求的流程一般为:
1、使用new XMLHttpRequest()或new ActiveXObject()插件的方式创建xhr对象。
2、通过xhr.open(...)的方式建立连接。
3、使用xhr.setRequestHeader(..)设置请求头信息
4、监听onreadystatechange事件,注册回调函数处理数据。
5、xhr.send(...)发生请求。
上面就是ajax的简单封装了,不过这么简陋的代码投入到生产中一般会被人打死。可以优化的地方太多,比如:提前浏览器特性检测、良好的API接口,对不同业务需求进行Ajax请求缓存优化等等,再如我们实际开发中会遇到很多问题:
看下jQuery的ajax请求的优雅写法:
首先因为jQuery的模块写的比较复杂(1200多行呢。。。),所以本篇blog只讲解Ajax请求的部分,response部分留到下次讲。
以下仅代表本人拙见,有错误或疑问之处欢迎之处~
jQuery的ajax的request部分应该有:预过滤器(ajaxPrefilter)、请求分发器(ajaxTransport)、json和script类型处理、jsonp的实现、请求头信息的处理和jQuery.ajax这个主方法。
先看ajaxPrefilter和ajaxTransport的构造器:
ajaxTransport的API文档是这么写的:描述: 创建一个对象,用于处理Ajax数据的实际传输。
很明显可以看到这两个方法只是分别往对应的prefilters和transports的dataType中添加对应的处理函数func。
而他们进行探测的方法是inspectPrefiltersOrTransports:
jQuery
c537
提供了一系列的预过滤器和分发器来处理常见dataType(如:script、json、jsonp)和跨域问题,在ajax发起请求之前做过滤处理,然后获取正确的transport对象来进行分发请求。
以上就是ajax的预过滤器和请求分发器了,jQuery通过这种预处理的方式将不同dataType的请求都提供了统一的处理接口,通过inspect transports获得正确的transport对象,然后使用统一的send接口发送请求,使用hack的方式处理了跨域请求,对内部$.ajax主方法完全解耦分离,还顺带给用户提供了过滤器和分发器功能。真是高明。
ajax的头信息就简单的说下好了,jqXHR(fake xhr)提供了一系列的方法来设置、获取头信息,另外在ajaxSettings中提供了cache选项来设置是否从缓存中获取数据。
而ajax主方法自从jQuery1.5之后就使用了Deferred延迟对象重写了:
以上就是jQuery的ajax方法比较完整的流程了。
ajax的response部分和其他的零散部分留到下次再讲。
允许转载,请带上出处http://blog.csdn.net/z905951024 by denied.
)
首先来看下传统的Ajax请求代码:
function doAjax(config){ var url = config.url, complete = config.complete, xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); xhr.open('post', url); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { complete(xhr.responseText); } } } xhr.send(config.data || null); return xhr; }
Ajax请求的流程一般为:
1、使用new XMLHttpRequest()或new ActiveXObject()插件的方式创建xhr对象。
2、通过xhr.open(...)的方式建立连接。
3、使用xhr.setRequestHeader(..)设置请求头信息
4、监听onreadystatechange事件,注册回调函数处理数据。
5、xhr.send(...)发生请求。
上面就是ajax的简单封装了,不过这么简陋的代码投入到生产中一般会被人打死。可以优化的地方太多,比如:提前浏览器特性检测、良好的API接口,对不同业务需求进行Ajax请求缓存优化等等,再如我们实际开发中会遇到很多问题:
跨域 json的格式 dataType AJAX乱码问题 页面缓存 状态的跟踪 不同平台兼容相信任何一个经验丰富的开发者都有遇到过上面的问题,每一个问题都令人头疼,所以得感谢jQuery提供的Ajax模块(jQuery大法好~)。
看下jQuery的ajax请求的优雅写法:
$.post(url, params).then(function(){ console.log('done'); }, function(){ console.log('fail'); });不错!jQuery的接口留的就是这么优雅。真想给jQuery点32个赞~
首先因为jQuery的模块写的比较复杂(1200多行呢。。。),所以本篇blog只讲解Ajax请求的部分,response部分留到下次讲。
以下仅代表本人拙见,有错误或疑问之处欢迎之处~
jQuery的ajax的request部分应该有:预过滤器(ajaxPrefilter)、请求分发器(ajaxTransport)、json和script类型处理、jsonp的实现、请求头信息的处理和jQuery.ajax这个主方法。
先看ajaxPrefilter和ajaxTransport的构造器:
//addToPrefiltersOrTransports作为jQuery.ajaxPrefilter和jQuery.ajaxTransport的构造器,他们的方法都是通过addToPrefiltersOrTransports来构建一个闭包生成的函数,用于维持传进来的structure // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { // dataTypeExpression is optional and defaults to "*" return function( dataTypeExpression, func ) { if ( typeof dataTypeExpression !== "string" ) { func = dataTypeExpression; dataTypeExpression = "*"; } var dataType, i = 0, dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || []; if ( jQuery.isFunction( func ) ) { // For each dataType in the dataTypeExpression while ( (dataType = dataTypes[i++]) ) { // Prepend if requested if ( dataType.charAt( 0 ) === "+" ) { dataType = dataType.slice( 1 ) || "*"; (structure[ dataType ] = structure[ dataType ] || []).unshift( func ); // Otherwise append } else { //structure的dataType列表中push对应的过滤器处理函数来 (structure[ dataType ] = structure[ dataType ] || []).push( func ); } } } }; }ajaxPrefilter的API文档是这么写的:描述: 在每个请求之前被发送和
$.ajax()处理它们前处理,设置自定义Ajax选项或修改现有选项。
ajaxTransport的API文档是这么写的:描述: 创建一个对象,用于处理Ajax数据的实际传输。
很明显可以看到这两个方法只是分别往对应的prefilters和transports的dataType中添加对应的处理函数func。
而他们进行探测的方法是inspectPrefiltersOrTransports:
//inspectPrefiltersOrTransports是一个prefilters和transports的探测器 // Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { //options为$.ajaxSettings var inspected = {}, //是否探测transports seekingTransport = ( structure === transports ); function inspect( dataType ) { var selected; //防止重复探测 inspected[ dataType ] = true; //fire该structure[ dataType ]中的所有处理函数 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) { options.dataTypes.unshift( dataTypeOrTransport ); //递归探测处理函数返回的dataType,防止后添加的处理函数没有执行 inspect( dataTypeOrTransport ); return false; } else if ( seekingTransport ) { //如果dataTypeOrTransport可转为true,则停止探测 return !( selected = dataTypeOrTransport ); } }); return selected; } return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); }ajaxPrefilter和ajaxTransport初始化给部分类型添加了对应的过滤器和分发器,如下:
// Handle cache's special case and global //处理缓存选项和设置跨域请求方式、禁止fire全局events jQuery.ajaxPrefilter( "script", function( s ) { if ( s.cache === undefined ) { s.cache = false; } if ( s.crossDomain ) { s.type = "GET"; s.global = false; } }); // Detect, normalize options and install callbacks for jsonp requests //像普通的方式处理json、jsonp格式的数据 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { var callbackName, overwritten, responseContainer, 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" ) { //略... // Delegate to script return "script"; } }); jQuery.ajaxTransport(function( options ) { // Cross domain only allowed if supported through XMLHttpRequest //返回一个处理非跨域的transport对象 if ( !options.crossDomain || support.cors ) { var callback; return { send: function( headers, complete ) { //略... }, abort: function() { if ( callback ) { callback( undefined, true ); } } }; } }); // Bind script tag hack transport jQuery.ajaxTransport( "script", function(s) { // This transport only deals with cross domain requests //返回一个处理跨域的transport对象 if ( s.crossDomain ) { var script, head = document.head || jQuery("head")[0] || document.documentElement; return { send: function( _, callback ) { //略... }, abort: function() { if ( script ) { script.onload( undefined, true ); } } }; } });
jQuery
c537
提供了一系列的预过滤器和分发器来处理常见dataType(如:script、json、jsonp)和跨域问题,在ajax发起请求之前做过滤处理,然后获取正确的transport对象来进行分发请求。
以上就是ajax的预过滤器和请求分发器了,jQuery通过这种预处理的方式将不同dataType的请求都提供了统一的处理接口,通过inspect transports获得正确的transport对象,然后使用统一的send接口发送请求,使用hack的方式处理了跨域请求,对内部$.ajax主方法完全解耦分离,还顺带给用户提供了过滤器和分发器功能。真是高明。
ajax的头信息就简单的说下好了,jqXHR(fake xhr)提供了一系列的方法来设置、获取头信息,另外在ajaxSettings中提供了cache选项来设置是否从缓存中获取数据。
而ajax主方法自从jQuery1.5之后就使用了Deferred延迟对象重写了:
ajax: function( url, options ) { // If url is an object, simulate pre-1.5 signature if ( typeof url === "object" ) { options = url; url = undefined; } // Force options to be an object options = options || {}; var //一大堆变量我给删了 s = jQuery.ajaxSetup( {}, options ), // Callbacks context callbackContext = s.context || s, // Context for global events is callbackContext if it is a DOM node or jQuery collection globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? jQuery( callbackContext ) : jQuery.event, // Deferreds,主延迟对象,将jqXHR做成一个promise对象 deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory"), // Fake xhr jqXHR = { //一大堆方法我给删了 }; // Attach deferreds //给jqXHR提供方便的API接口给用户 deferred.promise( jqXHR ).complete = completeDeferred.add; jqXHR.success = jqXHR.done; jqXHR.error = jqXHR.fail; // Remove hash character (#7531: and string promotion) // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) // Handle falsy url in the settings object (#10093: consistency with old signature) // We also use the url parameter if available s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); // Alias method option to type as per ticket #12004 s.type = options.method || options.type || s.method || s.type; // Extract dataTypes list s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; // A cross-domain request is in order when we have a protocol:host:port mismatch 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" ) ) ) ); } // Convert data if not already a string if ( s.data && s.processData && typeof s.data !== "string" ) { s.data = jQuery.param( s.data, s.traditional ); } //进行ajax过滤处理 // Apply prefilters inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); // If request was aborted inside a prefilter, stop there if ( state === 2 ) { return jqXHR; } // We can fire global events as of now if asked to // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) //是否触发全局事件 fireGlobals = jQuery.event && s.global; // Watch for a new set of requests //一组ajax请求时,在第一个ajax发起时触发ajaxStart事件 if ( fireGlobals && jQuery.active++ === 0 ) { jQuery.event.trigger("ajaxStart"); } // Uppercase the type s.type = s.type.toUpperCase(); //设置头信息和判断缓存的也给我删了 // Allow custom headers/mimetypes and early abort if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { // Abort if not done already and return return jqXHR.abort(); } // aborting is no longer a cancellation strAbort = "abort"; // Install callbacks on deferreds //添加ajaxSettings中配置的对应函数 for ( i in { success: 1, error: 1, complete: 1 } ) { jqXHR[ i ]( s[ i ] ); } // Get transport //获得transport对象 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); // If no transport, we auto-abort if ( !transport ) { done( -1, "No Transport" ); } else { jqXHR.readyState = 1; // Send global event //触发ajaxSend事件 if ( fireGlobals ) { globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); } // Timeout if ( s.async && s.timeout > 0 ) { timeoutTimer = setTimeout(function() { jqXHR.abort("timeout"); }, s.timeout ); } try { state = 1; //done方法作为请求完成的complete函数调用 transport.send( requestHeaders, done ); } catch ( e ) { // Propagate exception as error if not done if ( state < 2 ) { done( -1, e ); // Simply rethrow otherwise } else { throw e; } } } // Callback for when everything is done function done( status, nativeStatusText, responses, headers ) { var isSuccess, success, error, response, modified, statusText = nativeStatusText; //response的处理操作又给我删了 // Success/Error //fire对应的回调列表 if ( isSuccess ) { deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); } else { deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); } // Status-dependent callbacks jqXHR.statusCode( statusCode ); statusCode = undefined; //触发ajaxSuccess或者ajaxError事件 if ( fireGlobals ) { globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", [ jqXHR, s, isSuccess ? success : error ] ); } // Complete completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); //触发ajaxComplete事件 if ( fireGlobals ) { globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger("ajaxStop"); } } } //返回jqXHR对象,该对象是一个Promise对象 return jqXHR; }首先给jqXHR添加对应的接口,设置头信息和进行过滤操作,然后获取正确的transport对象,使用transport的send方法发起请求,,最后返回jqXHR。在done方法中处理response,最后延迟对象触发成功或失败的函数列表。其中在对应的时机触发对应的全局事件。
以上就是jQuery的ajax方法比较完整的流程了。
ajax的response部分和其他的零散部分留到下次再讲。
允许转载,请带上出处http://blog.csdn.net/z905951024 by denied.
相关文章推荐
- jQuery-AJAX模块解析-response部分
- struts2 + ajax(由前台的form提交数据到后台,再根据form所调用返回获取的后台json格式的数据返回到前端,然后前端用jquery对json数据进行解析)==》》涉及文件上传的部分
- struts2 + ajax(由前台的form提交数据到后台,再根据form所调用返回获取的后台json格式的数据返回到前端,然后前端用jquery对json数据进行解析)==》》涉及非文件上传的部分
- jquery通过ajax方式获取json数据和解析
- JQuery——Ajax之XMLHTTPRequest对象
- 实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法
- AJAX部分---php-jquery-ajax;
- jquery通过ajax-json访问java后台传递参数,通过request.getParameter获取不到参数的说明
- jquery+ajax 实例 全解析
- HttpServletRequest的部分方法解析
- php proxy for jquery ajax cross site request
- jQuery+ajax读取并解析XML文件的方法
- mysql内核源代码深度解析 缓冲池 LRU模块 全面分析(bufferpool部分二)
- AJAX用jquery解析servlet返回回来的XML 数据
- Jquery $.ajax 解析json
- [jquery,ajax] Ajax实例全解析
- jquery通过ajax方式获取json数据和解析
- ajax json jquery解析后台返回的数组
- 使用 jQuery,第 3 部分: 用 jQuery 和 Ajax 构建富 Internet 应用程序
- ajax: jquery get request