Chrome Sendrequest-fout: TypeError: het omzetten van de cirkelvormige structuur naar JSON

Ik heb het volgende …

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

die het volgende oproepen ..

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

Mijn code bereikt echter nooit “ZOMG HIER”, maar laat de volgende foutmelding tijdens het uitvoeren van chrome.extension.sendRequest

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

Heeft iemand enig idee wat dit veroorzaakt?


Antwoord 1, Autoriteit 100%

Het betekent dat het object dat u in het verzoek doorgeeft (ik denk dat het pagedoc) heeft, een cirkelvormige referentie, zoiets als:

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

JSON.Stringifykan geen structuren zoals deze converteren.

N.B.: Dit zou het geval zijn met DOM-knooppunten, die kringverwijzingen hebben, zelfs als ze niet aan de DOM-structuur zijn gekoppeld. Elke node heeft een ownerDocumentdie in de meeste gevallen verwijst naar document. documentheeft een verwijzing naar de DOM-structuur op zijn minst via document.bodyen document.body.ownerDocumentverwijst terug naar documentopnieuw, wat slechts éénis van meerdere kringverwijzingen in de DOM-structuur.


Antwoord 2, autoriteit 27%

Volgens de JSON-documenten bij Mozilla, JSON.Stringifyheeft een tweede parameter censordie kan worden gebruikt om onderliggende items te filteren/negeren tijdens het ontleden van de boom. Maar misschien kunt u de kringverwijzingen vermijden.

In Node.js kunnen we dat niet. Dus we kunnen zoiets als dit doen:

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

Het resultaat:

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

Helaas lijken er maximaal 30 iteraties te zijn voordat het automatisch aanneemt dat het circulair is. Anders zou dit moeten werken. Ik heb zelfs areEquivalentvan hiergebruikt, maar dan JSON.Stringifygenereert nog steeds de uitzondering na 30 iteraties. Toch is het goed genoeg om een fatsoenlijke weergave van het object op topniveau te krijgen, als je het echt nodig hebt. Misschien kan iemand dit echter verbeteren? In Node.js voor een HTTP-verzoekobject krijg ik:

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

Ik heb hier een kleine Node.js-module voor gemaakt: https://github.com/ericmuyser/stringy Voel je vrij om te verbeteren/bij te dragen!


Antwoord 3, autoriteit 11%

Eén benadering is het verwijderen van objecten en functies van het hoofdobject. En verstrengel de eenvoudigere vorm

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

Antwoord 4, autoriteit 8%

Normaal gebruik ik het circular-json npm-pakket om dit op te lossen.

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

Opmerking: circular-json is verouderd, ik gebruik nu flatted (van de maker van 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"}]

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


Antwoord 5, autoriteit 3%

Gebaseerd op het antwoord van zainengineer… Een andere benadering is om een diepe kopie van het object te maken en cirkelvormige verwijzingen te strippen en het resultaat te stringen.

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

Antwoord 6

Dit is misschien geen gerelateerd antwoord, maar deze link Cirkelverwijzingen detecteren en corrigeren in JavaScriptkan nuttig zijn om objectente detecteren die circulaire afhankelijkheid veroorzaken.


Antwoord 7

Ik los dit probleem op NodeJS als volgt op:

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

Antwoord 8

Voor mijn geval kreeg ik die foutmelding toen ik de functie asyncop mijn server gebruikte om documenten op te halen met mangoest. Het bleek dat de reden was dat ik vergat awaitin te voeren voordat ik de methode find({})aanroep. Het toevoegen van dat onderdeel loste mijn probleem op.


Antwoord 9

Ik heb dezelfde fout ondervonden toen ik het onderstaande bericht probeerde op te bouwen met jQuery. De kringverwijzing vindt plaats wanneer reviewerNameper ongeluk werd toegewezen aan msg.detail.reviewerName. JQuery’s .val() loste het probleem op, zie laatste regel.

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

Antwoord 10

Dit werkt en vertelt u welke eigenschappen circulair zijn. Het maakt het ook mogelijk om het object te reconstrueren met de referenties

 JSON.stringifyWithCircularRefs = (function() {
    const refs = new Map();
    const parents = [];
    const path = ["this"];
    function clear() {
      refs.clear();
      parents.length = 0;
      path.length = 1;
    }
    function updateParents(key, value) {
      var idx = parents.length - 1;
      var prev = parents[idx];
      if (prev[key] === value || idx === 0) {
        path.push(key);
        parents.push(value);
      } else {
        while (idx-- >= 0) {
          prev = parents[idx];
          if (prev[key] === value) {
            idx += 2;
            parents.length = idx;
            path.length = idx;
            --idx;
            parents[idx] = value;
            path[idx] = key;
            break;
          }
        }
      }
    }
    function checkCircular(key, value) {
      if (value != null) {
        if (typeof value === "object") {
          if (key) { updateParents(key, value); }
          let other = refs.get(value);
          if (other) {
            return '[Circular Reference]' + other;
          } else {
            refs.set(value, path.join('.'));
          }
        }
      }
      return value;
    }
    return function stringifyWithCircularRefs(obj, space) {
      try {
        parents.push(obj);
        return JSON.stringify(obj, checkCircular, space);
      } finally {
        clear();
      }
    }
  })();

Voorbeeld waarbij veel van de ruis is verwijderd:

{
    "requestStartTime": "2020-05-22...",
    "ws": {
        "_events": {},
        "readyState": 2,
        "_closeTimer": {
            "_idleTimeout": 30000,
            "_idlePrev": {
                "_idleNext": "[Circular Reference]this.ws._closeTimer",
                "_idlePrev": "[Circular Reference]this.ws._closeTimer",
                "expiry": 33764,
                "id": -9007199254740987,
                "msecs": 30000,
                "priorityQueuePosition": 2
            },
            "_idleNext": "[Circular Reference]this.ws._closeTimer._idlePrev",
            "_idleStart": 3764,
            "_destroyed": false
        },
        "_closeCode": 1006,
        "_extensions": {},
        "_receiver": {
            "_binaryType": "nodebuffer",
            "_extensions": "[Circular Reference]this.ws._extensions",
        },
        "_sender": {
            "_extensions": "[Circular Reference]this.ws._extensions",
            "_socket": {
                "_tlsOptions": {
                    "pipe": false,
                    "secureContext": {
                        "context": {},
                        "singleUse": true
                    },
                },
                "ssl": {
                    "_parent": {
                        "reading": true
                    },
                    "_secureContext": "[Circular Reference]this.ws._sender._socket._tlsOptions.secureContext",
                    "reading": true
                }
            },
            "_firstFragment": true,
            "_compress": false,
            "_bufferedBytes": 0,
            "_deflating": false,
            "_queue": []
        },
        "_socket": "[Circular Reference]this.ws._sender._socket"
    }
}

Om te reconstrueren roept u JSON.parse() aan en doorloopt u de eigenschappen op zoek naar de tag [Circular Reference]. Hak dat dan af en… evalueer… het met thisingesteld op het root-object.

Evalueer niets dat kan worden gehackt. Het is beter om string.split('.')te doen en vervolgens de eigenschappen op naam op te zoeken om de referentie in te stellen.


Antwoord 11

In mijn geval ben ik gewoon vergeten om async/wait te gebruiken tijdens het bouwen van de route:

app.get('/products', async (req, res) => {
    const products = await Product.find();
    res.send(products );
});

Antwoord 12

Ik kreeg dezelfde fout met jQuery formvaliadator, maar toen ik een console.log binnen success: function verwijderde, werkte het.


Antwoord 13

Node.js v10.22.1 (de versie die draait op onze GitLab CI-server) heeft, wat ik beschouw, een foutieve kringverwijzingsdetector. De lokaal draaiende versie (v12.8.0) is slim genoeg om te weten dat het geen echte kringverwijzing is.

Ik voeg dit antwoord toe voor het geval iemand anders hetzelfde probleem heeft en hun object eigenlijk geen kringverwijzing is.

Dit was het oorspronkelijke antwoordobject:

var res = {
    "status":"OK",
    "message":"Success",
    "errCode":":",
    "data":"",
    "appCfg":{
        "acp_age":"2yy",
        "acp_us":"yes",
        "mode":"admin",
        "version":"v1.21.07.1"
    },
    "reqID":59833,
    "email":{
        "status":"OK",
        "message":"Success"
    },
    "emailStatus":"sent"
}

Het dacht dat res.email.statushetzelfde was als res.status. Het is slechts een tekstelement, dus niet cirkelvormig, maar de naam en waarde struikelde kennelijk de JSON.Strationify Parser op.

Ik heb de res.emailsub-object verwijderen en alles is prima. Ik probeerde onafhankelijke statussen te verzamelen en gedetailleerde berichten van alle unieke acties die werden uitgevoerd tijdens de serveroproep. Ik heb het naar het element ingeschakeld res.emailStatusdie ook in het bovenstaande voorbeeld is opgenomen.


Antwoord 14

In mijn geval gebruik ik reageer native en probeerde

te debuggen

console.log(JSON.stringify(object))

en kreeg de fout:

TypeError: Converting circular structure to JSON

Het lijkt erop dat ik het object aan de console aan de console kan krijgen door gewoon gewoon te gebruiken:

console.log(object)

Other episodes