web-dev-qa-db-ja.com

Chromeの送信要求エラー:TypeError:循環構造からJSONへの変換

私は以下を持っています...

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

何がこれを引き起こしているのか、誰かに何か考えがありますか?

347
Skizit

それはあなたがリクエストで渡すオブジェクト(私はそれがpagedocであると思う)が循環参照を持っていることを意味します、何か:

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

JSON.stringifyはこのような構造を変換することはできません。

N.B. :これは、DOMツリーにアタッチされていなくても、循環参照を持つDOMノードの場合に当てはまります。各ノードは、ほとんどの場合ownerDocumentを参照するdocumentを持ちます。 documentは少なくともdocument.bodyを通じてDOMツリーへの参照を持ち、document.body.ownerDocumentは再びdocumentを参照します。これはDOMツリー内の複数の循環参照のうち、 one のみです。

457
Felix Kling

MozillaのJSONドキュメント によると、JSON.Stringifyには、ツリーを解析している間に子項目をフィルタリング/無視するために使用できる2番目のパラメータ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ここから を使ったことさえありますが、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]"
}

私はここでこれを行うために小さなNode.jsモジュールを作成しました: https://github.com/ericmuyser/stringy 改善してください/貢献してください!

116
Eric Muyser

1つの方法は、メインオブジェクトからオブジェクトと機能を削除することです。そしてより単純な形を文字列化する

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

私は通常これを解決するために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

20
user3139574

これは関連する答えではないかもしれませんが、このリンク JavaScriptで循環参照を検出して修正する は循環依存を引き起こしている オブジェクト を検出するのに役立ちます。

5

私はこのように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
MiF

以下のメッセージを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
2
izilotti

Zainengineerの答えに基づくと...もう1つの方法は、オブジェクトの詳細コピーを作成し、循環参照を削除して結果を文字列化することです。

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

私はjQueryのformvaliadatorと同じエラーを得ていたが、私は成功:関数内のconsole.logを削除したとき、それはうまくいった。

0
Azmeer