2011-01-27 17 views
298

Tengo el siguiente ...Chrome sendRequest error: TypeError: Conversión de estructura circular a JSON

chrome.extension.sendRequest({ 
    req: "getDocument", 
    docu: pagedoc, 
    name: 'name' 
}, function(response){ 
    var efjs = response.reply; 
}); 

que llama a la siguiente ..

case "getBrowserForDocumentAttribute": 
    alert("ZOMG HERE"); 
    sendResponse({ 
    reply: getBrowserForDocumentAttribute(request.docu,request.name) 
    }); 
    break; 

Sin embargo, mi código nunca alcanza " ZOMG AQUÍ", sino más bien arroja el siguiente error durante la ejecución de chrome.extension.sendRequest

Uncaught TypeError: Converting circular structure to JSON 
chromeHidden.JSON.stringify 
chrome.Port.postMessage 
chrome.initExtension.chrome.extension.sendRequest 
suggestQuery 

¿Hay alguien ¿Tienes alguna idea de lo que está causando esto?

+1

Usted está tratando de enviar un objeto que tiene referencias circulares en el mismo. ¿Qué es 'pagedoc'? –

+0

¿Qué quieres decir? – Skizit

+6

¿Qué quiero decir con qué? 1. ¿Cuál es el valor de 'pagedoc'? 2. Referencia circular: 'a = {}; a.b = a; ' –

Respuesta

390

Esto significa que el objeto se pasa en la solicitud (supongo que es pagedoc) tiene una referencia circular, algo así como:

var a = {}; 
a.b = a; 

JSON.stringify no puede convertir estructuras de este tipo.

N.B.: Este sería el caso con los nodos DOM, que tienen referencias circulares, incluso si no están adjuntos al árbol DOM. Cada nodo tiene un ownerDocument que se refiere a document en la mayoría de los casos. document tiene una referencia al árbol DOM al menos a través de document.body y document.body.ownerDocument de nuevo a document, que es solamente uno de referencias circulares múltiples en el árbol DOM.

+2

¡Gracias! Esto explica el problema que tengo. ¿Pero cómo la referencia circular presente en los objetos DOM no causa ningún problema? ¿JSON podría stringificar un objeto 'document'? – asgs

+3

@asgs: * * causa problemas, al menos en Chrome. Firefox parece ser un poco más inteligente al respecto, pero no sé exactamente qué está haciendo. –

+30

+1 para la advertencia de que un objeto DOM es circular. ¡Gracias! – charltoons

2

He experimentado el mismo error al intentar compilar el mensaje a continuación con jQuery. La referencia circular ocurre cuando reviewerName se estaba asignando por error al msg.detail.reviewerName. JQuery's .val() corrigió el problema, mira la última línea.

var reviewerName = $('reviewerName'); // <input type="text" id="taskName" />; 
var msg = {"type":"A", "detail":{"managerReview":true} }; 
msg.detail.reviewerName = reviewerName; // Error 
msg.detail.reviewerName = reviewerName.val(); // Fixed 
103

Según the JSON docs at Mozilla, JSON.Stringify tiene un segundo parámetro censor que se puede utilizar para filtrar/ignore artículos infantiles al analizar el árbol. Sin embargo, quizás puedas evitar las referencias circulares.

En Node.js no podemos. Por lo que podemos hacer algo como esto:

function censor(censor) { 
    var i = 0; 

    return function(key, value) { 
    if(i !== 0 && typeof(censor) === 'object' && typeof(value) == 'object' && censor == value) 
     return '[Circular]'; 

    if(i >= 29) // seems to be a harded maximum of 30 serialized objects? 
     return '[Unknown]'; 

    ++i; // so we know we aren't using the original object anymore 

    return value; 
    } 
} 

var b = {foo: {bar: null}}; 

b.foo.bar = b; 

console.log("Censoring: ", b); 

console.log("Result: ", JSON.stringify(b, censor(b))); 

El resultado:

Censoring: { foo: { bar: [Circular] } } 
Result: {"foo":{"bar":"[Circular]"}} 

Desafortunadamente parece que hay un máximo de 30 iteraciones antes de que asume automáticamente que es circular. De lo contrario, esto debería funcionar. Incluso utilicé areEquivalentfrom here, pero JSON.Stringify todavía arroja la excepción después de 30 iteraciones. Aún así, es lo suficientemente bueno para obtener una representación decente del objeto en un nivel superior, si realmente lo necesita. Sin embargo, tal vez alguien puede mejorar sobre esto? En Node.js para una solicitud de objeto HTTP, estoy recibiendo:

{ 
"limit": null, 
"size": 0, 
"chunks": [], 
"writable": true, 
"readable": false, 
"_events": { 
    "pipe": [null, null], 
    "error": [null] 
}, 
"before": [null], 
"after": [], 
"response": { 
    "output": [], 
    "outputEncodings": [], 
    "writable": true, 
    "_last": false, 
    "chunkedEncoding": false, 
    "shouldKeepAlive": true, 
    "useChunkedEncodingByDefault": true, 
    "_hasBody": true, 
    "_trailer": "", 
    "finished": false, 
    "socket": { 
     "_handle": { 
      "writeQueueSize": 0, 
      "socket": "[Unknown]", 
      "onread": "[Unknown]" 
     }, 
     "_pendingWriteReqs": "[Unknown]", 
     "_flags": "[Unknown]", 
     "_connectQueueSize": "[Unknown]", 
     "destroyed": "[Unknown]", 
     "bytesRead": "[Unknown]", 
     "bytesWritten": "[Unknown]", 
     "allowHalfOpen": "[Unknown]", 
     "writable": "[Unknown]", 
     "readable": "[Unknown]", 
     "server": "[Unknown]", 
     "ondrain": "[Unknown]", 
     "_idleTimeout": "[Unknown]", 
     "_idleNext": "[Unknown]", 
     "_idlePrev": "[Unknown]", 
     "_idleStart": "[Unknown]", 
     "_events": "[Unknown]", 
     "ondata": "[Unknown]", 
     "onend": "[Unknown]", 
     "_httpMessage": "[Unknown]" 
    }, 
    "connection": "[Unknown]", 
    "_events": "[Unknown]", 
    "_headers": "[Unknown]", 
    "_headerNames": "[Unknown]", 
    "_pipeCount": "[Unknown]" 
}, 
"headers": "[Unknown]", 
"target": "[Unknown]", 
"_pipeCount": "[Unknown]", 
"method": "[Unknown]", 
"url": "[Unknown]", 
"query": "[Unknown]", 
"ended": "[Unknown]" 
} 

he creado un módulo de Node.js pequeño para hacer esto aquí: https://github.com/ericmuyser/stringy dude para mejorar/contribuir!

+9

Es la primera vez que veo pasar una función que devuelve una función autoejecutable que devuelve una función normal. Creo que entiendo por qué se hizo esto, pero no creo que hubiera encontrado esa solución yo mismo, y creo que podría recordar esta técnica mejor si pudiera ver otros ejemplos donde este _setup_ es necesario. Dicho esto, ¿podría señalar alguna literatura sobre este _setup/technique_ (por falta de una palabra mejor) o similares? – Shawn

+1

+1 a Shawn. Por favor elimine ese IEFE, es absolutamente inútil e ilegible. – Bergi

+0

thx para señalar el censor arg! permite depurar problemas circulares. en mi caso, tenía una matriz de jquery en la que supongo que tendría una matriz normal. ambos se ven similares en el modo de impresión de depuración. Sobre el IEFE, los veo frecuentemente usados ​​en lugares donde no hay absolutamente necesidad de ellos y estoy de acuerdo con Shawn y Bergi en que este es solo el caso. – citykid

29

Un enfoque consiste en quitar objetos y funciones del objeto principal.Y stringify la forma más simple

function simpleStringify (object){ 
    var simpleObject = {}; 
    for (var prop in object){ 
     if (!object.hasOwnProperty(prop)){ 
      continue; 
     } 
     if (typeof(object[prop]) == 'object'){ 
      continue; 
     } 
     if (typeof(object[prop]) == 'function'){ 
      continue; 
     } 
     simpleObject[prop] = object[prop]; 
    } 
    return JSON.stringify(simpleObject); // returns cleaned up JSON 
}; 
+1

Respuesta perfecta para mí. Tal vez la palabra clave 'función' se perdió? –

3

resuelvo este problema en NodeJS así:

var util = require('util'); 

// Our circular object 
var obj = {foo: {bar: null}, a:{a:{a:{a:{a:{a:{a:{hi: 'Yo!'}}}}}}}}; 
obj.foo.bar = obj; 

// Generate almost valid JS object definition code (typeof string) 
var str = util.inspect(b, {depth: null}); 

// Fix code to the valid state (in this example it is not required, but my object was huge and complex, and I needed this for my case) 
str = str 
    .replace(/<Buffer[ \w\.]+>/ig, '"buffer"') 
    .replace(/\[Function]/ig, 'function(){}') 
    .replace(/\[Circular]/ig, '"Circular"') 
    .replace(/\{ \[Function: ([\w]+)]/ig, '{ $1: function $1() {},') 
    .replace(/\[Function: ([\w]+)]/ig, 'function $1(){}') 
    .replace(/(\w+): ([\w :]+GMT\+[\w \(\)]+),/ig, '$1: new Date("$2"),') 
    .replace(/(\S+): ,/ig, '$1: null,'); 

// Create function to eval stringifyed code 
var foo = new Function('return ' + str + ';'); 

// And have fun 
console.log(JSON.stringify(foo(), null, 4)); 
12

Normalmente uso el paquete circular-json npm para resolver esto.

// Felix Kling's example 
var a = {}; 
a.b = a; 
// load circular-json module 
var CircularJSON = require('circular-json'); 
console.log(CircularJSON.stringify(a)); 
//result 
{"b":"~"} 

https://www.npmjs.com/package/circular-json

0

que estaba recibiendo el mismo error con formvaliadator jqurty, pero cuando me quita un console.log dentro éxito: la función, funcionó.

1

Basado en la respuesta de zainengineer ... Otro enfoque es hacer una copia profunda del objeto y quitar referencias circulares y escribir el resultado.

function cleanStringify(object) { 
 
    if (object && typeof object === 'object') { 
 
     object = copyWithoutCircularReferences([object], object); 
 
    } 
 
    return JSON.stringify(object); 
 

 
    function copyWithoutCircularReferences(references, object) { 
 
     var cleanObject = {}; 
 
     Object.keys(object).forEach(function(key) { 
 
      var value = object[key]; 
 
      if (value && typeof value === 'object') { 
 
       if (references.indexOf(value) < 0) { 
 
        references.push(value); 
 
        cleanObject[key] = copyWithoutCircularReferences(references, value); 
 
        references.pop(); 
 
       } else { 
 
        cleanObject[key] = '###_Circular_###'; 
 
       } 
 
      } else if (typeof value !== 'function') { 
 
       cleanObject[key] = value; 
 
      } 
 
     }); 
 
     return cleanObject; 
 
    } 
 
} 
 

 
// Example 
 

 
var a = { 
 
    name: "a" 
 
}; 
 

 
var b = { 
 
    name: "b" 
 
}; 
 

 
b.a = a; 
 
a.b = b; 
 

 
console.log(cleanStringify(a)); 
 
console.log(cleanStringify(b));

Cuestiones relacionadas