这是在Chrome中提示的错误
IE中提示为:完成该操作所需的数据还不可使用。
出现场景:
在使用jQuery的ajax且网络很慢、设置了timeout的情况下,直接不判断ajax的readyState而直接取responseText将出会错(此时xhr对象可能只有两个属性可用:
responseXML、readyState)。
例如如果使用Ext+jQuery进行的开发中,ext-jQuery-adapter-debug.js中的代码有:
Ext.lib.Ajax = function(){ var createComplete = function(cb){ return function(xhr, status){ if((status == 'error' || status == 'timeout') && cb.failure){ cb.failure.call(cb.scope||window, createResponse(cb, xhr)); }else if(cb.success){ cb.success.call(cb.scope||window, createResponse(cb, xhr)); } }; }; var createResponse = function(cb, xhr){ var headerObj = {}, headerStr, t, s; try { headerStr = xhr.getAllResponseHeaders(); Ext.each(headerStr.replace(/\r\n/g, '\n').split('\n'), function(v){ t = v.indexOf(':'); if(t >= 0){ s = v.substr(0, t).toLowerCase(); if(v.charAt(t + 1) == ' '){ ++t; } headerObj[s] = v.substr(t + 1); } }); } catch(e) {} return { responseText: xhr.responseText, responseXML : xhr.responseXML, argument: cb.argument, status: xhr.status, statusText: xhr.statusText, getResponseHeader : function(header){return headerObj[header.toLowerCase()];}, getAllResponseHeaders : function(){return headerStr} }; }; return { request : function(method, uri, cb, data, options){ var o = { type: method, url: uri, data: data, timeout: cb.timeout, complete: createComplete(cb) }; if(options){ var hs = options.headers; if(options.xmlData){ o.data = options.xmlData; o.processData = false; o.type = (method ? method : (options.method ? options.method : 'POST')); if (!hs || !hs['Content-Type']){ o.contentType = 'text/xml'; } }else if(options.jsonData){ o.data = typeof options.jsonData == 'object' ? Ext.encode(options.jsonData) : options.jsonData; o.processData = false; o.type = (method ? method : (options.method ? options.method : 'POST')); if (!hs || !hs['Content-Type']){ o.contentType = 'application/json'; } } if(hs){ o.beforeSend = function(xhr){ for(var h in hs){ if(hs.hasOwnProperty(h)){ xhr.setRequestHeader(h, hs[h]); } } } } } jQuery.ajax(o); }, formRequest : function(form, uri, cb, data, isUpload, sslUri){ jQuery.ajax({ type: Ext.getDom(form).method ||'POST', url: uri, data: jQuery(form).serialize()+(data?'&'+data:''), timeout: cb.timeout, complete: createComplete(cb) }); }, isCallInProgress : function(trans){ return false; }, abort : function(trans){ return false; }, serializeForm : function(form){ return jQuery(form.dom||form).serialize(); } }; }();
在jquery回调的时候,它调用 createResponse方法,而在createResponse方法中并未进行检测。
jQuery中的ajax并未监听ajax对象的onreadystatechange,而是使用定时器setInterval去检测它的状态readyState或是直接传入timeout将视为请求结束。对使用timeout结束的请求,它调用其abort方法,取消请求。
// Wait for a response to come back var onreadystatechange = function(isTimeout){ // The request was aborted, clear the interval and decrement jQuery.active if (xhr.readyState == 0) { if (ival) { // clear poll interval clearInterval(ival); ival = null; // Handle the global AJAX counter if ( s.global && ! --jQuery.active ) jQuery.event.trigger( "ajaxStop" ); } // The transfer is complete and the data is available, or the request timed out } else if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) { requestDone = true; // clear poll interval if (ival) { clearInterval(ival); ival = null; } status = isTimeout == "timeout" ? "timeout" : !jQuery.httpSuccess( xhr ) ? "error" : s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" : "success"; if ( status == "success" ) { // Watch for, and catch, XML document parse errors try { // process the data (runs the xml through httpData regardless of callback) data = jQuery.httpData( xhr, s.dataType, s ); } catch(e) { status = "parsererror"; } } // Make sure that the request was successful or notmodified if ( status == "success" ) { // Cache Last-Modified header, if ifModified mode. var modRes; try { modRes = xhr.getResponseHeader("Last-Modified"); } catch(e) {} // swallow exception thrown by FF if header is not available if ( s.ifModified && modRes ) jQuery.lastModified[s.url] = modRes; // JSONP handles its own success callback if ( !jsonp ) success(); } else jQuery.handleError(s, xhr, status); // Fire the complete handlers complete(); if ( isTimeout ) xhr.abort(); // Stop memory leaks if ( s.async ) xhr = null; } }; if ( s.async ) { // don't attach the handler to the request, just poll it instead var ival = setInterval(onreadystatechange, 13); // Timeout checker if ( s.timeout > 0 ) setTimeout(function(){ // Check to see if the request is still happening if ( xhr && !requestDone ) onreadystatechange( "timeout" ); }, s.timeout); }
其中ival类似于系统调用了onreadystatechange方法。
提示,在使用ajax在进行处理结果的时候,需要先判断它的readyState和status两个值。不然容易出错