首页 文章

Chrome sendrequest错误:TypeError:将循环结构转换为JSON

提问于
浏览
342

我有以下......

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

它调用以下..

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

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

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

有谁知道是什么原因引起的?

9 回答

  • 114

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

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

    JSON.stringify 无法转换此类结构 .

    N.B. :DOM节点就是这种情况,它们具有循环引用,即使它们没有附加到DOM树 . 在大多数情况下,每个节点都有一个 ownerDocument ,它指的是 document . document 至少通过 document.body 引用DOM树, document.body.ownerDocument 再次引用 document ,这只是DOM树中多个循环引用之一 .

  • 5

    根据the JSON docs at MozillaJSON.Stringify 有第二个参数 censor ,可用于在解析树时过滤/忽略子项 . 但是,也许你可以避免循环引用 .

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

    结果:

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

    不幸的是,在它自动假设为循环之前,似乎最多有30次迭代 . 否则,这应该工作 . 我甚至使用 areEquivalent from here,但 JSON.Stringify 仍然在30次迭代后抛出异常 . 它仍然是'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'得到:

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

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

  • 0

    一种方法是从主对象中剥离对象和函数 . 并将更简单的形式字符串化

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

    我通常使用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":"~"}
    

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

  • 31

    这可能不是相关的答案,但是这个链接Detecting and fixing circular references in JavaScript可能有助于检测导致循环依赖的 objects .

  • 2

    我在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, '{ $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

    尝试使用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
    
  • 20

    基于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));
    
  • 0

    我在使用jQuery formvaliadator时遇到了同样的错误,但是当我在success:function中删除了一个console.log时,它运行起来了 .

相关问题