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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏小灰灰

二维码服务拓展(支持logo,圆角logo,背景图,颜色配置)

二维码的基础服务拓展 zxing 提供了二维码一些列的功能,在日常生活中,可以发现很多二维码并不仅仅是简单的黑白矩形块,有的添加了文字,加了logo,定制颜色...

84910
来自专栏程序员的酒和故事

通过httprouter和redis框架搭建restful api服务

HttpRouter is a lightweight high performance HTTP request router (also called mu...

48710
来自专栏coding...

swift3.0 CoreGraphics绘图-实现画板Demo地址

设置触摸时间,开始时记录第一个点并重绘(不重绘就没有只画一个点得效果),移动时不断记录并重绘。

1264
来自专栏游戏杂谈

as3与php 上传多张图片demo

2、在一次添加的图片中如果超出最大上传数,忽略本次选中的所有图片(又得重新选一次,此现象普通存在于目前各大网站的flash批量上传中)

2022
来自专栏张高兴的博客

张高兴的 UWP 开发笔记:手机状态栏 StatusBar

3495
来自专栏MasiMaro 的技术博文

菜单的使用

2)弹出式菜单:一般在顶级菜单上都有很多菜单项,单击这些菜单项时会弹出一个下拉式的菜单项,我们点击的这个菜单称为弹出式菜单

1204
来自专栏张高兴的博客

张高兴的 UWP 开发笔记:汉堡菜单进阶

4406
来自专栏一个爱瞎折腾的程序猿

asp.net mvc项目自定义区域

2.Code:在Global.asax中添加注册区域-->AreaRegistration.RegisterAllAreas();

1661
来自专栏Golang语言社区

go语言实现通过FTP库自动上传web日志

因为平时管理的web服务器都是VM服务器,为节省硬盘空间,一般给虚拟机分配的硬盘空间都比较小,只有8G,因为,保存不了多少日志,所以每天都需要把每台WEB日志转...

4333
来自专栏Bingo的深度学习杂货店

HTML5新特性

本章的主要内容有: ---- [1] 用于媒体回放的 video 和audio 元素 [2] HTML5拖放 [3] canvas简单应用 [4] Web存储:...

5105

扫码关注云+社区

领取腾讯云代金券