Подтвердить что ты не робот

Исходный JSON.parse IE8 вызывает переполнение стека

TL; DR: Добавление каких-либо не встроенных функций в Array.prototype И Function.prototype заставит исходный JSON-анализатор IE8 получить переполнение стека при анализе любого JSON, содержащего массив, но только тогда, когда вы также передаете функцию reviver в JSON.parse().

Это началось как вопрос, но я ответил на свой собственный оригинальный вопрос, поэтому теперь я спрошу: может ли кто-нибудь подумать об обходном пути для этой ошибки IE8, которая не включает в себя устранение всех JS-библиотек, которые изменяют Array. прототип и Function.prototype?

Оригинальный вопрос:

У меня есть около 13k данных JSON для разбора. Структура данных - это объект с единственным значением, являющимся вложенным массивом.

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

Я использую json2.js, который отдает предпочтение браузерному родному JSON.parse, когда он доступен. Я передаю функцию reviver в JSON.parse для правильной обработки дат. Когда IE8 находится в режиме эмуляции IE7 (что заставляет его использовать парсер json2.js, основанный на script), все работает нормально. Когда IE8 находится в режиме IE8 (что заставляет его использовать собственный анализатор JSON на основе браузера), он взрывается с ошибкой "из пространства стека". Firefox и Chrome, конечно же, отлично работают с их парсерами JSON, основанными на браузере.

Я сузился до этого: если я передам в JSON.parse даже функцию do-nothing reviver, исходный парсер IE8 получит переполнение стека. Если я не передаю функцию reviver, собственный парсер IE8 отлично работает, за исключением того, что он правильно не обрабатывает даты.

// no error:
JSON.parse(stuff);

// "out of stack space" error:
JSON.parse(stuff, function(key, val) { return val; });

Я буду играть со своими данными JSON, чтобы увидеть, может ли меньше данных или меньше вложенности данных избежать ошибки, но мне было интересно, видел ли кто-нибудь это раньше или какие-либо другие предлагаемые варианты работы. IE8 уже достаточно медленный, было бы позором отключить собственный JSON для этого браузера из-за этой ошибки.

UPDATE: В других случаях, при использовании разных данных JSON, я получаю ошибку javascript "$ lineinfo is undefined", когда я использую собственный синтаксический анализатор IE8 с функцией reviver, и нет ошибки, если я не использую функцию reviver, Строка "$ lineinfo" не отображается нигде ни в одном из моих исходных кодов.

ОБНОВЛЕНИЕ 2: На самом деле эта проблема, по-видимому, вызвана прототипом 1.6.0.3. Мне не удалось воспроизвести его на отдельной тестовой странице, пока я не добавлю в библиотеку Prototype.

ОБНОВЛЕНИЕ 3:

Причина, по которой prototype.js ломает собственный синтаксический анализатор JSON IE8, заключается в следующем: добавление каких-либо не встроенных функций в Array.prototype И Function.prototype заставит исходный JSON-анализатор IE8 получить переполнение стека при анализе любого 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>
4b9b3361

Ответ 2

Решение состоит в том, чтобы удалить собственный JSON.parse на IE8 и заменить его на JSON.parse из json2.js lib:

Добавить

<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) {
...

После этого синтаксический разбор должен работать снова.

Одна из проблем с этим подходом заключается в том, что метод parse json2.js медленнее, чем собственный.

Ответ 3

У меня был этот вопрос без каких-либо принятых ответов, довольно долгое время, поэтому, чтобы избавиться от него, я сам отвечу.

Eric Law в Microsoft говорит:

Команда 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 (пытаетесь ли вы запускать несколько экземпляров Internet Explorer при одной и той же установке Windows?) или ваш ввод плох.

Вы также можете прочитать Native JSON в IE8. Этот конкретный пункт может представлять интерес:

Дополнительный аргумент revive - пользователь определенная функция, используемая для пост-анализа изменения. Полученный объект или массив пересекается рекурсивно, функция применяется к каждому члену. Каждое значение элемента заменяется на значение, возвращаемое редактором. Если reviver возвращает null, объект член удален. Обход и призыв к postorder. Это верно; каждый объект "возрожден" после, все его члены "Revived'.

В приведенном выше параграфе объясняется, почему моя функция reviver выглядит так, как она есть. Моя первая попытка тестового кода заключалась в следующем:

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

Очевидно, что если эта функция reversion применяется к address node выше, после применения ко всем ее дочерним элементам, я полностью уничтожил объект address.

Конечно, если тест вашего реверсинга так же прост, как вы описываете в своем вопросе, маловероятно, что какая-то глобальная циклическая ссылка приведет к проблеме, которую вы видите. Я все еще думаю, что это указывает на сломанный Internet Explorer или плохие данные.

Можете ли вы изменить свой вопрос и опубликовать образец фактических данных, которые обнаруживают проблему, поэтому я могу попробовать ее здесь?

Ответ 5

Расширение этой проблемы (которая все еще присутствует в IE9), является встроенной функцией JSON.stringify, сбой IE, когда есть:

  • график больших объектов
  • Объектный граф ссылается на объекты данных jQuery.
  • граф объекта является круглым.

Мы не уверены, какая именно причина вызывает крах.

Наше решение в этом случае состояло в том, чтобы использовать функцию replacer для функции stringify для возврата null к определенному свойству объекта и прекратить перемещение графика объекта.

Ответ 6

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

преобразует строку в объект в IE 8.