IE8原生JSON.parse错误导致堆栈溢出
TL;DR:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析任何包含数组的JSON时出现堆栈溢出,但仅当您还将一个reviver函数传递到JSON.parse()中时才会发生。 这一开始只是一个问题,但我回答了我自己的原始问题,所以现在我要问:有人能想出一个解决IE8 bug的方法,不包括消除所有修改Array.prototype和Function.prototype的JS库吗 原始问题: 我有大约13k的JSON数据要解析。数据的结构是一个具有单个值的对象,该值是一个嵌套数组IE8原生JSON.parse错误导致堆栈溢出,json,internet-explorer-8,Json,Internet Explorer 8,TL;DR:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析任何包含数组的JSON时出现堆栈溢出,但仅当您还将一个reviver函数传递到JSON.parse()中时才会发生。 这一开始只是一个问题,但我回答了我自己的原始问题,所以现在我要问:有人能想出一个解决IE8 bug的方法,不包括消除所有修改Array.prototype和Function.prototype的JS库吗 原始问题: 我有大约13k的JSON数据
{ 'value':[[ stuff ], [ more stuff], [ etc ]] }
我使用的是json2.js,它在可用时遵从浏览器原生的JSON.parse。我将向JSON.parse传递一个reviver函数,以正确处理日期。当IE8处于IE7仿真模式(这导致它使用基于脚本的json2.js解析器)时,一切正常。当IE8处于IE8模式(这导致它使用浏览器原生JSON解析器)时,它会出现“堆栈空间不足”错误。当然,Firefox和Chrome可以很好地使用浏览器原生JSON解析器
我已经把范围缩小到这样:如果我将一个不做任何事情的恢复器函数传递到JSON.parse中,IE8本机解析器就会得到堆栈溢出。如果我没有传入任何reviver函数,IE8本机解析器就可以正常工作,只是不能正确解析日期
// no error:
JSON.parse(stuff);
// "out of stack space" error:
JSON.parse(stuff, function(key, val) { return val; });
我将使用我的JSON数据,看看减少数据或数据嵌套是否可以避免错误,但我想知道是否有人以前见过这一点,或者有任何其他建议的解决方法。IE8已经足够慢了,如果因为这个bug而禁用该浏览器的本机JSON,那将是一个耻辱
更新:在其他情况下,使用不同的JSON数据时,当我使用IE8本机解析器和reviver函数时,会出现javascript错误“$lineinfo未定义”,如果不使用reviver函数,则不会出现错误。字符串“$lineinfo”在我的任何源代码中都不会出现
更新2:实际上,这个问题似乎是由原型1.6.0.3引起的。在原型库中添加之前,我无法在单独的测试页面中复制它
更新3:
prototype.js破坏IE8本机JSON解析器的原因是:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析任何包含数组的JSON时出现堆栈溢出,但仅当您还将reviver函数传递到JSON.parse()中时
原型库向Array.Prototype和Function.Prototype添加函数,但这同样适用于执行相同操作的任何其他库。IE JSON解析器中的这个bug是由Prototype和Ext暴露的,而不是jQuery。我还没有测试过任何其他框架
这是这个问题的一个完全独立的再现。如果删除Function.prototype行或Array.prototype行,或从JSON字符串中删除数组,则不会出现“堆栈空间不足”错误
Function.prototype.test1=Function(){};
Array.prototype.test2=函数(){};
window.onload=函数()
{
警报(JSON.parse('{foo:[1,2,3]}',函数(k,v){return v;}));
}
在这里似乎可以正常工作:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Test</title>
</head>
<body>
<pre>
<script type="text/javascript">
document.writeln('');
var o = {
"firstName": "cyra",
"lastName": "richardson",
"address": {
"streetAddress": "1 Microsoft way",
"city": "Redmond",
"state": "WA",
"postalCode": 98052
},
"phoneNumbers": [
"425-777-7777",
"206-777-7777"
]
};
var s = JSON.stringify(o);
document.writeln(s);
var p = JSON.parse(s, function (key, val) {
if (typeof val === 'string') return val + '-reviver!';
else return val;
});
dump(p);
function dump(o) {
for (var a in o) {
if (typeof o[a] === 'object') {
document.writeln(a + ':');
dump(o[a]);
} else {
document.writeln(a + ' = ' + o[a]);
}
}
}
</script>
</pre>
</body>
</html>
显然,如果在应用于上面的地址
节点的所有子节点之后,将此恢复器函数应用于该节点,则我已经完全销毁了地址
对象
当然,如果对你的救世主的测试像你在问题中描述的那样简单,那么不太可能是某种全球性的循环引用导致了你所看到的问题。我仍然认为它指向一个坏的Internet Explorer或坏数据
你能发布一个显示问题的实际数据样本,让我在这里试试吗?我已经有一段时间没有被接受的答案了,所以为了解决这个问题,我会自己回答 微软的Eric Law说:
JavaScript团队报告说,这是JavaScript引擎中的一个已知问题 这是刚刚修补好的。
解决方案是删除IE8上的本机JSON.parse,并从库中将其替换为JSON.parse: 加: 之后,解析将再次工作 这种方法的一个问题是json2.js解析方法比本机方法慢
将字符串转换为IE8中的对象时,本机JSON.stringify函数会在以下情况下使IE崩溃:
我们在这个实例中的解决方法是在stringify函数上使用replacer函数,在特定对象属性上返回null,并阻止对象图被遍历。谢谢-事实证明Prototype不知何故是罪魁祸首+1为彻底的回应!JavaScript团队报告说,这是JavaScript引擎中的一个已知问题。谢谢。我也有同样的问题。我需要JSON.parser来处理IE8。我做了你的推荐,它对我不起作用。它适用于任何其他不同的浏览器。有什么想法吗?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Test</title>
</head>
<body>
<pre>
<script type="text/javascript">
document.writeln('');
var o = {
"firstName": "cyra",
"lastName": "richardson",
"address": {
"streetAddress": "1 Microsoft way",
"city": "Redmond",
"state": "WA",
"postalCode": 98052
},
"phoneNumbers": [
"425-777-7777",
"206-777-7777"
]
};
var s = JSON.stringify(o);
document.writeln(s);
var p = JSON.parse(s, function (key, val) {
if (typeof val === 'string') return val + '-reviver!';
else return val;
});
dump(p);
function dump(o) {
for (var a in o) {
if (typeof o[a] === 'object') {
document.writeln(a + ':');
dump(o[a]);
} else {
document.writeln(a + ' = ' + o[a]);
}
}
}
</script>
</pre>
</body>
</html>
function (key, val) {
return val + '-reviver!';
}
<script type="text/javascript">
if (jQuery.browser.msie && jQuery.browser.version.indexOf("8.") === 0) {
if (typeof JSON !== 'undefined') {
JSON.parse = null;
}
}
<script>
<script type="text/javascript" src="json2.js"></script>
// json2.js
...
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
...
eval(Ext.decode("{"foo":"bar"}"));