IE8本机JSON.parse错误导致堆栈溢出

时间:2009-08-17 16:20:02

标签: json internet-explorer-8

TL; DR:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析包含数组的任何JSON时获得堆栈溢出,但仅限于你还将一个reviver函数传递给JSON.parse()。

这开始是一个问题,但我回答了我自己的原始问题,所以现在我会问:任何人都可以想到解决这个IE8错误的解决办法,不涉及删除所有修改数组的JS库。 prototype和Function.prototype?

原始问题:

我要解析大约13k的JSON数据。数据的结构是一个具有单个值的对象,该值是嵌套数组。

{ 'value':[[ stuff ], [ more stuff], [ etc ]] }

我正在使用json2.js,它在可用时遵循浏览器本机JSON.parse。我正在将一个reviver函数传递给JSON.parse来正确处理日期。当IE8处于IE7仿真模式(导致它使用基于脚本的json2.js解析器)时,一切正常。当IE8处于IE8模式(导致它使用浏览器本机JSON解析器)时,它会出现“堆栈空间不足”错误。当然,Firefox和Chrome可以与浏览器原生的JSON解析器一起使用。

我已将其缩小到这一点:如果我将一个do-nothing reviver函数传递给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已经足够慢了,因为这个错误而禁用该浏览器的原生JSON将是一种耻辱。

更新:在其他情况下,使用不同的JSON数据,当我使用具有reviver功能的IE8本机解析器时,我收到javascript错误“$ lineinfo is undefined”,如果我不使用reviver函数则没有错误。字符串“$ lineinfo”不会出现在我的任何源代码中。

更新2:实际上,这个问题似乎是由原型1.6.0.3引起的。在我添加到Prototype库中之前,我无法在隔离的测试页中重现它。

更新3:

prototype.js打破IE8原生JSON解析器的原因是:将任何非内置函数添加到Array.prototype和Function.prototype将导致IE8本机JSON解析器在解析任何JSON时获得堆栈溢出包含一个数组,但只有当你还将一个reviver函数传递给JSON.parse()。

Prototype库为Array.prototype和Function.prototype添加了函数,但这同样适用于执行相同操作的任何其他库。 IE JSON解析器中的这个错误由​​Prototype和Ext公开,但不是jQuery。我还没有测试过任何其他框架。

这是一个完全独立的问题再现。如果删除Function.prototype行或Array.prototype行,或从JSON字符串中删除该数组,则不会出现“堆栈空间不足”错误。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
<script type="text/javascript">

Function.prototype.test1 = function() { };
Array.prototype.test2 = function() { };

window.onload = function()
{
    alert(JSON.parse('{ "foo": [1,2,3] }', function(k,v) { return v; }));
}

</script>
</head>
<body>

</body>
</html>

6 个答案:

答案 0 :(得分:6)

答案 1 :(得分:5)

解决方案是删除IE8上的本机JSON.parse并将其替换为json2.js lib中的JSON.parse:

添加:

<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​​ON.parse替换为自己的版本

// json2.js
...
if (typeof JSON.parse !== 'function') {
    JSON.parse = function (text, reviver) {
...

之后解析应该再次起作用。

这种方法的一个问题是json2.js解析方法比原生方法慢。

答案 2 :(得分:3)

我已经有了这个问题,并且没有可接受的答案,但是为了摆脱它,我会自己回答。

微软的Eric Law说:

  

JavaScript小组报告这是JavaScript引擎中的一个已知问题。

答案 3 :(得分:2)

这似乎工作正常:

<!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 8安装损坏(您是否尝试在同一Windows安装上运行Internet Explorer的多个副本?)或输入错误。

您可能还想阅读Native JSON in IE8。可能会对此特定段落感兴趣:

  

可选的 revive参数是一个用户   用于post parse的定义函数   变化。生成的对象或数组   递归遍历, reviver   功能适用于每个成员。   每个成员值都替换为    reviver 返回的值。如果   reviver返回null,即对象   会员被删除。遍历和   关于复活的呼吁是在   后序。那就对了;每个对象   在所有成员之后'复活'   “恢复“。

上面的段落解释了为什么我的reviver功能看起来像它的方式。我对测试代码的第一次尝试是:

function (key, val) {
    return val + '-reviver!';
}

显然,如果将 reviver 函数应用于上面的address节点后应用于其所有子节点,我就完全销毁了address对象。

当然,如果 reviver 的测试与您在问题中描述的一样简单,那么某些全局循环引用不太可能导致您遇到的问题。我仍然认为它指向Internet Explorer损坏或数据不良。

你可以edit your question发布一个展示问题的实际数据样本,以便我可以在这里试试吗?

答案 4 :(得分:2)

此问题的扩展(IE9中仍然存在)是本机JSON.stringify函数在存在以下情况时崩溃IE:

  1. 大对象图
  2. 对象图引用jQuery'data'对象。
  3. 对象图是圆形的。
  4. 我们不确定哪个特定点导致崩溃。

    我们在这个实例中的解决方法是在stringify函数上使用replacer函数在特定对象属性上返回null并停止遍历对象图。

答案 5 :(得分:-2)

eval(Ext.decode("{"foo":"bar"}"));

正在将转换为 IE 8 中的对象。