Erro de solicitação de envio do Chrome: TypeError: conversão da estrutura circular em JSON

Eu tenho o seguinte …

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

que chama o seguinte ..

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

No entanto, meu código nunca alcança “ZOMG AQUI”, mas gera o seguinte erro ao executar chrome.extension.sendRequest

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

Alguém tem alguma idéia do que está causando isso?

Isso significa que o object que você passa no pedido (eu acho que é pagedoc ) tem uma referência circular, algo como:

 var a = {}; ab = a; 

JSON.stringify não pode converter estruturas como esta.

NB : Este seria o caso dos nós DOM, que possuem referências circulares, mesmo que não estejam anexados à tree DOM. Cada nó possui um ownerDocument que se refere ao document na maioria dos casos. document tem uma referência à tree DOM pelo menos através de document.body e document.body.ownerDocument volta ao document novamente, que é apenas uma das várias referências circulares na tree DOM.

De acordo com os documentos JSON no Mozilla , o JSON.Stringify possui um segundo parâmetro censor que pode ser usado para filtrar / ignorar itens filhos durante a análise da tree. No entanto, talvez você possa evitar as referências circulares.

No Node.js não podemos. Então podemos fazer algo assim:

 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))); 

O resultado:

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

Infelizmente, parece haver um máximo de 30 iterações antes de assumir automaticamente que é circular. Caso contrário, isso deve funcionar. Eu até areEquivalent daqui , mas JSON.Stringify ainda lança a exceção após 30 iterações. Ainda assim, é bom o suficiente para obter uma representação decente do object em um nível superior, se você realmente precisar dele. Talvez alguém possa melhorar isso? Em Node.js para um object de solicitação HTTP, estou recebendo:

 { "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]" } 

Eu criei um pequeno módulo Node.js para fazer isso aqui: https://github.com/ericmuyser/stringy Sinta-se livre para melhorar / contribuir!

Uma abordagem é retirar objects e funções do object principal. E stringify a forma mais simples

 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 }; 

Eu normalmente uso o pacote circular-json npm para resolver isso.

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

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

Eu resolvo esse problema no NodeJS assim:

 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(//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)); 

Essa resposta pode não estar relacionada, mas este link Detectar e corrigir referências circulares no JavaScript pode ser útil para detectar objects que estão causando dependência circular.

Eu experimentei o mesmo erro ao tentar construir a mensagem abaixo com jQuery. A referência circular acontece quando reviewerName está sendo erroneamente atribuído a msg.detail.reviewerName . O .val de JQuery () corrigiu o problema, veja a última linha.

 var reviewerName = $('reviewerName'); // ; var msg = {"type":"A", "detail":{"managerReview":true} }; msg.detail.reviewerName = reviewerName; // Error msg.detail.reviewerName = reviewerName.val(); // Fixed 

Com base na resposta do zainengineer … Outra abordagem é fazer uma cópia profunda do object e remover referências circulares e restringir o 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" }; ba = a; ab = b; console.log(cleanStringify(a)); console.log(cleanStringify(b)); 

Eu estava recebendo o mesmo erro com formvaliadator jQuery, mas quando eu removi um console.log dentro do sucesso: function, funcionou.