IE8原生JSON.parse错误导致堆栈溢出

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数据

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崩溃:

  • 大对象图
  • 对象图引用jQuery“数据”对象
  • 对象图是圆形的
  • 我们不确定是哪一点导致了这次事故


    我们在这个实例中的解决方法是在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"}"));