616 Stimmen

Chrome sendrequest Fehler: TypeError: Umwandlung einer kreisförmigen Struktur in JSON

Ich habe die folgenden...

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

die das folgende aufruft.

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

Mein Code erreicht jedoch nie "ZOMG HERE", sondern gibt beim Ausführen den folgenden Fehler aus chrome.extension.sendRequest

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

Hat jemand eine Idee, was die Ursache dafür ist?

675voto

Felix Kling Punkte 751464

Es bedeutet, dass das Objekt, das Sie in der Anfrage übergeben (ich vermute, es ist pagedoc ) hat einen zirkulären Bezug, etwa so:

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

JSON.stringify kann solche Strukturen nicht konvertieren.

N.B.. : Dies wäre der Fall bei DOM-Knoten, die zirkuläre Referenzen haben, auch wenn sie nicht an den DOM-Baum angehängt sind. Jeder Knoten hat eine ownerDocument die sich auf document in den meisten Fällen. document hat einen Verweis auf den DOM-Baum mindestens durch document.body y document.body.ownerDocument verweist zurück auf document wieder, was nur eine von mehreren zirkulären Verweisen im DOM-Baum.

189voto

Eric Muyser Punkte 3503

Gemäß die JSON-Dokumente bei Mozilla , JSON.stringify hat einen zweiten Parameter replacer die verwendet werden kann, um Kinderelemente beim Parsen des Baums zu filtern/zu ignorieren. Vielleicht können Sie jedoch die zirkulären Verweise vermeiden.

In Node.js können wir das nicht. Also können wir etwas wie dies tun:

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

Das Ergebnis:

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

Leider scheint es ein Maximum von 30 Iterationen zu geben, bevor es automatisch annimmt, dass es sich um einen Kreis handelt. Ansonsten sollte dies funktionieren. Ich habe sogar areEquivalent von hier aber JSON.stringify löst nach 30 Iterationen immer noch die Ausnahme aus. Dennoch ist es gut genug, um eine anständige Darstellung des Objekts auf oberster Ebene zu erhalten, wenn man es wirklich braucht. Vielleicht kann jemand dies noch verbessern? In Node.js erhalte ich für ein HTTP-Request-Objekt:

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

Ich habe ein kleines Node.js-Modul erstellt, das dies ermöglicht: https://github.com/ericmuyser/stringy Fühlen Sie sich frei, etwas zu verbessern oder beizutragen!

90voto

zainengineer Punkte 11921

Eine Möglichkeit besteht darin, Objekte und Funktionen aus dem Hauptobjekt zu entfernen. Und die einfachere Form zu stringifizieren

function simpleStringify (object){
    // stringify an object, avoiding circular structures
    // https://stackoverflow.com/a/31557814
    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
};

53voto

user3139574 Punkte 1049

Normalerweise verwende ich das npm-Paket circular-json, um dieses Problem zu lösen.

// 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":"~"}

Hinweis: circular-json ist veraltet, ich verwende jetzt flatted (vom Erfinder von CircularJSON):

// ESM
import {parse, stringify} from 'flatted/esm';

// CJS
const {parse, stringify} = require('flatted/cjs');

const a = [{}];
a[0].a = a;
a.push(a);

stringify(a); // [["1","0"],{"a":"0"}]

von: https://www.npmjs.com/package/flatted

30voto

C.M. Punkte 359

Basierend auf der Antwort von zainengineer... Ein anderer Ansatz besteht darin, eine tiefe Kopie des Objekts zu erstellen, zirkuläre Referenzen zu entfernen und das Ergebnis zu stringifizieren.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X