【问题标题】:IE8 native JSON.parse bug causes stack overflowIE8 原生 JSON.parse 错误导致堆栈溢出
【发布时间】:2009-08-17 16:20:02
【问题描述】:

TL;DR: 将任何非内置函数添加到 Array.prototype AND Function.prototype 将导致 IE8 原生 JSON 解析器在解析任何包含数组的 JSON 时发生堆栈溢出,但仅当您还将 reviver 函数传递给 JSON.parse()。

这开始是一个问题,但我回答了我自己的原始问题,所以现在我要问:任何人都可以想到一个解决这个 IE8 错误的方法,它不涉及消除所有修改 Array.js 的库。原型和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 解析器配合得很好。

我已将其范围缩小为:如果我将一个无操作的 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 已经够慢了,因为这个 bug 而禁用该浏览器的原生 JSON 将是一种耻辱。

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

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

更新 3:

prototype.js 破坏 IE8 原生 JSON 解析器的原因是:将任何非内置函数添加到 Array.prototype AND 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>

【问题讨论】:

  • JavaScript 团队报告说这是 JavaScript 引擎中的一个已知问题。谢谢。

标签: json internet-explorer-8


【解决方案1】:
【解决方案2】:

一种解决方案是删除 IE8 上的原生 JSON.parse,并用 json2.js 库中的 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 将 JSON.parse 替换为自己的版本

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

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

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

【讨论】:

  • 我遇到了同样的问题。我需要 JSON.parser 才能在 IE8 上工作。我做了你的建议,它对我不起作用。它适用于任何其他不同的浏览器。有什么想法吗?
【解决方案3】:

这个问题我已经有很长一段时间没有公认的答案了,所以为了摆脱它,我会自己回答。

微软的 Eric Law 说:

JavaScript 团队报告说这是 JavaScript 引擎中的一个已知问题。

【讨论】:

    【解决方案4】:

    这里似乎可以正常工作:

    <!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 参数是用户 用于后解析的定义函数 变化。结果对象或数组 递归遍历,reviver 功能适用于每个成员。 每个成员值都替换为 reviver 返回的值。如果 reviver 返回 null,对象 成员被删除。遍历和 对 reviver 的调用在 后购。这是正确的;每个物体 所有成员都“复活”之后 “复活了”。

    上面的段落解释了为什么我的 reviver 函数看起来是这样的。我第一次尝试测试代码是:

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

    显然,如果这个 reviver 函数在应用到其所有子节点后应用到上面的 address 节点,我已经完全销毁了 address 对象。

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

    您能否edit your question 并发布一个显示问题的实际数据样本,以便我可以在这里尝试?

    【讨论】:

    • 谢谢 - 原来 Prototype 在某种程度上是罪魁祸首。 +1 以获得彻底的回应!
    【解决方案5】:

    这个问题的一个扩展(IE9 中仍然存在)是原生 JSON.stringify 函数在 IE 崩溃时崩溃:

    1. 大对象图
    2. 对象图引用 jQuery 'data' 对象。
    3. 对象图是圆形的。

    我们不确定导致崩溃的具体点。

    在这种情况下,我们的解决方法是在 stringify 函数上使用替换函数以在特定对象属性上返回 null 并停止遍历对象图。

    【讨论】:

      【解决方案6】:
      eval(Ext.decode("{"foo":"bar"}"));
      

      IE 8 中将字符串转换为对象。

      【讨论】:

        猜你喜欢
        • 2011-02-08
        • 1970-01-01
        • 2015-05-21
        • 2014-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多