web-dev-qa-db-fra.com

Chrome erreur sendrequest: TypeError: Conversion de structure circulaire en JSON

J'ai le suivant ...

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

qui appelle ce qui suit ..

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

Cependant, mon code n'atteint jamais "ZOMG HERE", mais renvoie l'erreur suivante lors de l'exécution de chrome.extension.sendRequest

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

Est-ce que quelqu'un a une idée de ce qui cause cela?

351
Skizit

Cela signifie que l'objet que vous transmettez dans la demande (je suppose que c'est pagedoc) a une référence circulaire, quelque chose comme:

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

JSON.stringify ne peut pas convertir de telles structures.

N.B.: Ce serait le cas des nœuds DOM, qui ont des références circulaires, même s'ils ne sont pas attachés à l'arborescence DOM. Chaque nœud a un ownerDocument qui fait référence à document dans la plupart des cas. document a une référence à l’arbre DOM au moins par le biais de document.body et document.body.ownerDocument renvoie à document, ce qui n’est que un de multiples références circulaires dans l’arbre DOM.

463
Felix Kling

Conformément à les documents JSON sur Mozilla , JSON.Stringify possède un deuxième paramètre censor qui peut être utilisé pour filtrer/ignorer les éléments enfants lors de l'analyse de l'arborescence. Cependant, vous pouvez peut-être éviter les références circulaires.

Dans Node.js, nous ne pouvons pas. Donc, nous pouvons faire quelque chose comme ça:

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

Le résultat:

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

Malheureusement, il semble y avoir un maximum de 30 itérations avant de supposer automatiquement qu'il est circulaire. Sinon, cela devrait fonctionner. J'ai même utilisé areEquivalentà partir d'ici , mais JSON.Stringify lève toujours l'exception après 30 itérations. Néanmoins, il est suffisant d'obtenir une représentation décente de l'objet au plus haut niveau, si vous en avez vraiment besoin. Peut-être que quelqu'un peut améliorer cela cependant? Dans Node.js pour un objet de requête HTTP, j'obtiens:

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

J'ai créé un petit module Node.js pour le faire ici: https://github.com/ericmuyser/stringy N'hésitez pas à améliorer/contribuer!

117
Eric Muyser

Une approche consiste à supprimer l'objet et les fonctions de l'objet principal. Et stringifier la forme plus 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
};
35
zainengineer

J'utilise normalement le paquet circular-json npm pour résoudre ce problème.

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

20
user3139574

Cela pourrait ne pas être une réponse liée, mais ce lien Détecter et corriger les références circulaires en JavaScript pourrait être utile pour détecter les objets qui causent dépendance circulaire.

5
Ramesh Papaganti

Je résous ce problème sur NodeJS comme ceci:

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

Basé sur la réponse de zainengineer ... Une autre approche consiste à créer une copie complète de l'objet et à supprimer les références circulaires afin de renforcer le résultat.

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));
4
C.M.

J'ai rencontré la même erreur en essayant de construire le message ci-dessous avec jQuery. La référence circulaire se produit lorsque reviewerName a été affecté par erreur à msg.detail.reviewerName. .Val () de JQuery a corrigé le problème, voir dernière ligne.

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
2
izilotti

La même erreur se produisait avec jQuery formvaliadator, mais lorsque j'ai supprimé un fichier console.log inside success: function, cela fonctionnait.

0
Azmeer