json internet-explorer-8

Error JSON.parse IE8 nativo provoca desbordamiento de pila



internet-explorer-8 (6)

He tenido esta pregunta sin respuestas aceptadas por bastante tiempo, así que para deshacerme de ella, la responderé yo mismo.

Eric Law en Microsoft dice:

El equipo de JavaScript informa que este es un problema conocido en el motor de JavaScript.

TL; DR: Agregar funciones no incorporadas a Array.prototype AND Function.prototype provocará que el analizador JSON nativo de IE8 obtenga un desbordamiento de la pila al analizar cualquier JSON que contenga una matriz, pero solo cuando también pase una función reviver en JSON.parse ().

Esto comenzó como una pregunta, pero respondí mi propia pregunta original, así que ahora voy a preguntar: ¿alguien puede pensar en una solución para este error IE8 que no implica la eliminación de todas las bibliotecas JS que modifican Array.prototype y Function .¿prototipo?

Pregunta original:

Tengo aproximadamente 13k de datos JSON para analizar. La estructura de los datos es un objeto con un único valor que es una matriz anidada.

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

Estoy usando json2.js, que se remite al navegador JSON.parse nativo cuando esté disponible. Paso una función reviver en JSON.parse para manejar las fechas correctamente. Cuando IE8 está en modo de emulación IE7 (lo que hace que use el analizador json2.js basado en script) todo funciona bien. Cuando IE8 está en modo IE8 (lo que hace que use el analizador JSON nativo del navegador) explota con un error de "falta de espacio en la pila". Firefox y Chrome, por supuesto, funcionan bien con sus analizadores JSON nativos del navegador.

Lo he reducido a esto: si paso incluso una función reviver do-nothing en JSON.parse, el analizador nativo IE8 obtiene el desbordamiento de la pila. Si paso sin función de reactivación, el analizador nativo IE8 funciona bien, excepto que no analiza las fechas correctamente.

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

Voy a jugar con mis datos JSON, para ver si menos datos o menos anidamiento de los datos pueden evitar el error, pero me preguntaba si alguien había visto esto antes, o si había sugerido algún otro tipo de solución alternativa. IE8 ya es lo suficientemente lento, sería una pena deshabilitar JSON nativo para ese navegador debido a este error.

ACTUALIZACIÓN: en otros casos, con diferentes datos JSON, obtengo un error de javascript "$ lineinfo no está definido" cuando uso el analizador nativo IE8 con una función reviver y no hay error si no uso la función reviver. La cadena "$ lineinfo" no aparece en ningún lugar de ninguno de mis códigos fuente.

ACTUALIZACIÓN 2: En realidad, este problema parece ser causado por el Prototipo 1.6.0.3. No pude reproducirlo en una página de prueba aislada hasta que agregué en la biblioteca Prototype.

ACTUALIZACIÓN 3:

El motivo por el cual prototype.js rompe el analizador JSON nativo de IE8 es este: agregar funciones no incorporadas a Array.prototype AND Function.prototype provocará que el analizador JSON nativo de IE8 obtenga un desbordamiento de la pila al analizar cualquier JSON que contenga una matriz , pero solo cuando también pasas una función reviver a JSON.parse ().

La biblioteca Prototype agrega funciones tanto a Array.prototype como a Function.prototype, pero esto se aplica igualmente a cualquier otra biblioteca que haga lo mismo. Este error en el analizador de IE JSON está expuesto por Prototype y Ext, pero no jQuery. No he probado otros marcos.

Aquí hay una reproducción completamente independiente del problema. Si elimina la línea Function.prototype, o la línea Array.prototype, o elimina la matriz de la cadena JSON, no obtendrá el error "out of stack space".

<!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>



Una solución es eliminar el JSON.parse nativo en IE8 y reemplazarlo con el JSON.parse de la lib json2.js :

Añadir:

<script type="text/javascript"> if (jQuery.browser.msie && jQuery.browser.version.indexOf("8.") === 0) { if (typeof JSON !== ''undefined'') { JSON.parse = null; } } <script>

... y luego incluir:

<script type="text/javascript" src="json2.js"></script>

Esto activará json2 para reemplazar el JSON.parse con su propia versión

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

Después de eso, el análisis debería funcionar de nuevo.

Un problema con este enfoque es que el método de análisis json2.js es más lento que el método nativo.


Una extensión de este problema (que todavía está presente en IE9), es la función JSON.stringify nativa bloquea IE cuando hay:

  1. un gran gráfico de objetos
  2. el gráfico del objeto hace referencia a los objetos de ''datos'' de jQuery.
  3. el gráfico del objeto es circular.

No estamos seguros de qué punto específico causa el colapso.

En este caso, nuestra solución fue utilizar una función de reemplazo en la función de stringify para devolver nulo en una propiedad de objeto particular y evitar que se atraviese el gráfico de objetos.


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

está transformando una Cadena en un Objeto en IE 8 .


Parece que funciona bien aquí:

<!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>

El problema es una instalación corrupta de Internet Explorer 8 (¿está intentando ejecutar varias copias de Internet Explorer en la misma instalación de Windows?) O su entrada es incorrecta.

Es posible que también desee leer Native JSON en IE8 . Este párrafo en particular puede ser de interés:

El argumento revivir opcional es una función definida por el usuario que se usa para los cambios de análisis posteriores. El objeto o matriz resultante se recorre recursivamente, la función reviver se aplica a cada miembro. Cada valor de miembro se reemplaza con el valor devuelto por el reanimador . Si el reanimador devuelve nulo, el miembro del objeto se elimina. El recorrido y la llamada al reanimador se realizan en postorder. Está bien; cada objeto es "revivido" después de que todos sus miembros son " revividos ".

El párrafo anterior explica por qué mi función reviver se ve de la manera que lo hace. Mi primer intento de código de prueba fue:

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

Obviamente, si esta función reviver se aplica al nodo de address arriba después de haber sido aplicado a todos sus elementos secundarios , he destruido completamente el objeto de address .

Por supuesto, si la prueba de su reviver es tan simple como usted describe en su pregunta, es poco probable que alguna referencia circular global esté dando lugar al problema que está viendo. Todavía creo que apunta a un Internet Explorer roto o datos incorrectos.

¿Puedes editar tu pregunta y publicar una muestra de datos reales que muestren el problema para que pueda probarlo aquí?