一段Ajax代码的思考
在平时写ajax调用的过程中,发起一个ajax调用经常是这么写的:
$.ajax({ url:'http://www.oschina.net',success:function(data){ //处理成功的返回..... } });
今天突然心血来潮,想改改写法,于是:
var jqXHR = $.ajax({ url:'http://www.oschina.net'}); jqXHR.done(function(data){ //处理成功的返回..... })
发现也是可以的,有两个疑问:
// Get 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 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; 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; } } } function done(xxxx) return jqXHR;
对于第一个疑问,可以确定的是,jqXHR对象在返回之前,已经发起了请求。那么如果返回jqXHR对象后,又做了很多事情,消耗了不少时间,再调用jqXHR.done()注册回调函数,是否来不及呢?jQuery是怎么保证回调函数被调用的呢?问题的关键就是jqXHR对象,它是一个Defer对象。Defer对象注册的回调函数是根据状态被调用的,如果注册函数的时候,Defer对象已经resolve了,那么相应的回调函数(done)会立即被调用,如果还没有resolve,那么这个回调函数还是会在resolve的时候被调用。
好了,问题解决。