INVALID_STATE_ERR: DOM Exception 11

这是在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两个值。不然容易出错

posted @ 2010-09-29 15:38  meteoric_cry  阅读(6519)  评论(0编辑  收藏  举报