Javascript Chrome 发送请求错误:TypeError:将循环结构转换为 JSON

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4816099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 14:15:15  来源:igfitidea点击:

Chrome sendrequest error: TypeError: Converting circular structure to JSON

javascriptjsongoogle-chromegoogle-chrome-extension

提问by Skizit

I've got the following...

我有以下...

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

which calls the following..

调用以下..

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

However, my code never reaches "ZOMG HERE" but rather throws the following error while running chrome.extension.sendRequest

但是,我的代码永远不会到达“ZOMG HERE”,而是在运行时抛出以下错误 chrome.extension.sendRequest

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

Does anyone have any idea what is causing this?

有谁知道是什么原因造成的?

回答by Felix Kling

It means that the object you pass in the request (I guess it is pagedoc) has a circular reference, something like:

这意味着您在请求中传递的对象(我猜是pagedoc)具有循环引用,例如:

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

JSON.stringifycannot convert structures like this.

JSON.stringify不能转换这样的结构。

N.B.: This would be the case with DOM nodes, which have circular references, even if they are not attached to the DOM tree. Each node has an ownerDocumentwhich refers to documentin most cases. documenthas a reference to the DOM tree at least through document.bodyand document.body.ownerDocumentrefers back to documentagain, which is only oneof multiple circular references in the DOM tree.

注意:DOM 节点就是这种情况,它们具有循环引用,即使它们没有附加到 DOM 树。在大多数情况下ownerDocument,每个节点都有一个引用documentdocument具有通过至少一个参考DOM树document.bodydocument.body.ownerDocument指回document再次,这是唯一一个在DOM树中的多个循环引用。

回答by Eric Muyser

As per the JSON docs at Mozilla, JSON.Stringifyhas a second parameter censorwhich can be used to filter/ignore children items while parsing the tree. However, perhaps you can avoid the circular references.

根据Mozilla 的 JSON 文档JSON.Stringify有第二个参数censor可用于在解析树时过滤/忽略子项。但是,也许您可​​以避免循环引用。

In Node.js we cannot. So we can do something like this:

在 Node.js 中我们不能。所以我们可以做这样的事情:

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

The result:

结果:

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

Unfortunately there seems to be a maximum of 30 iterations before it automatically assumes it's circular. Otherwise, this should work. I even used areEquivalentfrom here, but JSON.Stringifystill throws the exception after 30 iterations. Still, it's good enough to get a decent representation of the object at a top level, if you really need it. Perhaps somebody can improve upon this though? In Node.js for an HTTP request object, I'm getting:

不幸的是,在它自动假定它是循环之前似乎最多有 30 次迭代。否则,这应该有效。我什areEquivalent至从这里使用,但JSON.Stringify在 30 次迭代后仍然抛出异常。尽管如此,如果您真的需要它,那么在顶级获得对象的体面表示就足够了。也许有人可以改进这一点?在用于 HTTP 请求对象的 Node.js 中,我得到:

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

I created a small Node.js module to do this here: https://github.com/ericmuyser/stringyFeel free to improve/contribute!

我在这里创建了一个小的 Node.js 模块来做到这一点:https: //github.com/ericmuyser/stringy随时改进/贡献!

回答by zainengineer

One approach is to strip object and functions from main object. And stringify the simpler form

一种方法是从主对象中剥离对象和函数。并将更简单的形式串起来

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

回答by user3139574

I normally use the circular-json npm package to solve this.

我通常使用circular-json npm 包来解决这个问题。

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

Note: circular-json has been deprecated, I now use flatted (from the creator of CircularJSON):

注意:circular-json 已被弃用,我现在使用 flatted(来自 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"}]

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

来自:https: //www.npmjs.com/package/flatted

回答by C.M.

Based on zainengineer's answer... Another approach is to make a deep copy of the object and strip circular references and stringify the result.

基于 zainengineer 的回答......另一种方法是制作对象的深层副本并去除循环引用并对结果进行字符串化。

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

回答by Ramesh Papaganti

This might not be related answer, but this link Detecting and fixing circular references in JavaScriptmight helpful to detect objectswhich are causing circular dependency.

这可能不是相关的答案,但此链接 检测和修复 JavaScript 中的循环引用可能有助于检测导致循环依赖的对象

回答by MiF

I resolve this problem on NodeJS like this:

我在 NodeJS 上解决了这个问题,如下所示:

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, '{ : function  () {},')
    .replace(/\[Function: ([\w]+)]/ig, 'function (){}')
    .replace(/(\w+): ([\w :]+GMT\+[\w \(\)]+),/ig, ': new Date(""),')
    .replace(/(\S+): ,/ig, ': null,');

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

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

回答by izilotti

I have experienced the same error when trying to build the message below with jQuery. The circular reference happens when reviewerNamewas being mistakenly assigned to msg.detail.reviewerName. JQuery's .val() fixed the issue, see last line.

尝试使用 jQuery 构建下面的消息时,我遇到了同样的错误。循环引用发生在reviewerName错误地分配给msg.detail.reviewerName. JQuery 的 .val() 修复了这个问题,见最后一行。

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

回答by Azmeer

I was getting the same error with jQuery formvaliadator, but when I removed a console.log inside success: function, it worked.

我在使用 jQuery formvaliadator 时遇到了同样的错误,但是当我在 success: 函数中删除了 console.log 时,它起作用了。

回答by Mussa Charles

For my case I was getting that error when I was using asyncfunction on my server-side to fetch documents using mongoose. It turned out that the reason was I forgot to put awaitbefore calling find({})method. Adding that part fixed my issue.

就我而言,当我async在服务器端使用函数来使用 mongoose 获取文档时遇到了该错误。原来是我await在调用find({})方法之前忘记放了。添加该部分解决了我的问题。