2009-08-17 11 views
31

TL; DR: L'aggiunta di qualsiasi funzione non incorporata in Array.prototype AND Function.prototype farà sì che il parser JSON nativo IE8 ottenga uno stack overflow durante l'analisi di qualsiasi JSON che contiene un array, ma solo quando si passa anche una funzione Reviver in JSON.parse().IE8 nativo JSON.parse bug causa overflow dello stack

Questa iniziato come una domanda, ma ho risposto alla mia domanda iniziale, quindi ora mi chiedo: qualcuno può pensare a un work-around per questo bug IE8 che non coinvolge eliminando tutte le librerie JS che modificano Array.prototype e Function.prototype?

domanda originale:

ho circa 13k dei dati JSON da analizzare. La struttura dei dati è un oggetto con un singolo valore che è una matrice nidificata.

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

Sto utilizzando json2.js, che rimanda al browser nativo JSON.parse quando disponibile. Sto passando una funzione di reviver in JSON.parse per gestire correttamente le date. Quando IE8 è in modalità di emulazione IE7 (che fa sì che utilizzi il parser json2.js basato su script) tutto funziona correttamente. Quando IE8 è in modalità IE8 (che fa sì che utilizzi il parser JSON nativo del browser) si verifica un errore "out of stack space". Firefox e Chrome, ovviamente, funzionano bene con i loro parser JSON nativi del browser.

L'ho ristretto a questo: se passo in JSON.parse anche una funzione revisore del nulla fare, il parser nativo IE8 ottiene lo stack overflow. Se non passo in nessuna funzione di reviver, il parser nativo IE8 funziona bene, tranne che non analizza correttamente le date.

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

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

ho intenzione di giocare con i miei dati JSON, per vedere se meno dati o meno nidificazione dei dati possono evitare l'errore, ma mi chiedevo se qualcuno avesse visto prima, o ha avuto qualsiasi altro suggerito work-around. IE8 è già abbastanza lento, sarebbe un peccato disabilitare il JSON nativo per quel browser a causa di questo bug.

AGGIORNAMENTO: in altri casi, con dati JSON diversi, viene visualizzato un errore javascript "$ lineinfo non definito" quando utilizzo il parser IE8 nativo con una funzione reviver e nessun errore se non utilizzo alcuna funzione reviver. La stringa "$ lineinfo" non appare in nessuna parte del mio codice sorgente.

UPDATE 2: In realtà, questo problema sembra essere causato da Prototype 1.6.0.3. Non sono riuscito a riprodurlo in una pagina di test isolata finché non ho aggiunto la libreria Prototype.

UPDATE 3:

I prototype.js ragione rompe l'IE8 nativo parser JSON è questo: L'aggiunta di qualsiasi non-built-in per l'Array.prototype E Function.prototype causerà l'IE8 nativo parser JSON per ottenere un overflow dello stack durante l'analisi di qualsiasi JSON che contiene un array, ma solo quando si passa anche una funzione Reviver in JSON.parse().

La libreria Prototype aggiunge funzioni a Array.prototype e Function.prototype, ma ciò vale anche per qualsiasi altra libreria che fa la stessa cosa. Questo bug nel parser JSON di IE è esposto da Prototype ed Ext, ma non da jQuery. Non ho testato nessun altro framework.

Ecco una riproduzione completamente autonoma del problema. Se si rimuove la riga Function.prototype o la riga Array.prototype o si rimuove l'array dalla stringa JSON, non si otterrà l'errore "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> 
+3

Il team JavaScript segnala che si tratta di un problema noto nel motore JavaScript. Grazie. – EricLaw

+0

Grazie per avermelo fatto sapere. –

risposta

2

Sembra funzionare bene qui:

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

Il problema è sia un corrotto Internet Explorer 8 installare (stai cercando di eseguire più copie di Internet Explorer sulla stessa installazione di Windows?) O il tuo contributo è cattivo.

Si consiglia inoltre di leggere Native JSON in IE8. Questo particolare punto può essere di interesse:

L'invio facoltativo rivivere argomento è una funzione definita dall'utente usato per la post analizzare modifiche. L'oggetto o l'array risultante viene attraversato in modo ricorsivo, la funzione reviver viene applicata a ogni membro. Ogni valore membro viene sostituito con il valore restituito dal rever . Se il reviver restituisce null, il membro dell'oggetto viene cancellato. L'attraversamento e la chiamata su reviver sono fatti nel postorder . Giusto; ogni oggetto è 'revived' dopo tutti i suoi membri sono ' riattivato '.

Il paragrafo precedente spiega perché la mia funzione di reviver ha lo stesso aspetto. Il mio primo tentativo di codice di prova era:

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

Ovviamente se questa funzione reviver viene applicato al nodo address sopra dopo essere stato applicato a tutti i suoi figli, che ho completamente distrutto l'oggetto address.

Naturalmente, se il test del vostro reviver è così semplice come si descrive nella sua interrogazione, è improbabile che qualche riferimento circolare globale sta portando al problema si sta vedendo. Continuo a pensare che punti a un Internet Explorer rotto oa dati errati.

Puoi edit your question e pubblicare un campione di dati reali che presenta il problema, quindi posso provarlo qui?

+0

Grazie - si scopre che Prototype è in qualche modo il colpevole. +1 per la risposta completa! –

3

Ho avuto questa domanda senza risposte accettate per un po 'di tempo, quindi, per liberarmene, risponderò io stesso.

Eric Giurisprudenza presso Microsoft dice:

Il team JavaScript segnala che questo è un problema noto nel motore JavaScript.

5

Una soluzione è quella di rimuovere il JSON.parse nativo su IE8 e sostituirlo con il JSON.parsing dalla json2.js lib:

Add:

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

... e poi includono:

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

Questo attiverà json2 per sostituire il JSON.parse con una propria versione

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

Successivamente l'analisi dovrebbe funzionare di nuovo.

Un problema con questo approccio è che il metodo di analisi json2.js è più lento di quello nativo.

+0

Ho lo stesso problema. Ho bisogno che JSON.parser funzioni su IE8. Ho fatto la tua raccomandazione, non funziona per me. Funziona con qualsiasi altro browser. qualche idea? – user1471980

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

sta trasformando una stringa in un oggetto in IE 8.

2

Un'estensione di questo problema (che è ancora presente in IE9), è la funzione nativa JSON.stringify blocca IE quando ci sono:

  1. un grande oggetto riferimenti graph graph
  2. l'oggetto jQuery ' dati 'oggetti.
  3. il grafico dell'oggetto è circolare.

Non siamo sicuri di quale punto specifico causi l'incidente.

La nostra soluzione alternativa in questa istanza era quella di utilizzare una funzione di replacer sulla funzione stringify per restituire null su una particolare proprietà dell'oggetto e interrompere l'attraversamento del grafico dell'oggetto.

Problemi correlati