[javascript] Chrome sendrequest 오류 : 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

누구 든지이 원인을 알고 있습니까?



답변

그것은 당신이 요청에 전달하는 객체 ( pagedoc)가 순환 참조를 가지고 있음을 의미합니다 .

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

JSON.stringify 이와 같은 구조는 변환 할 수 없습니다.

NB : DOM 트리에 연결되지 않은 경우에도 순환 참조가있는 DOM 노드의 경우입니다. 각 노드에는 대부분의 경우 ownerDocument참조 하는 노드가 document있습니다. document관통 적어도 DOM 트리에 대한 참조를 보유 document.body하고 document.body.ownerDocument위로 지칭 document만, 이는 다시 하나 DOM 트리의 다수의 순환 참조.


답변

당으로 모질라에서 JSON 워드 프로세서 , JSON.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 여기 에서도 사용 했지만 JSON.Stringify30 회 반복 후에도 여전히 예외를 던졌습니다. 그래도 필요한 경우 최상위 수준에서 개체를 적절하게 표현할 수 있으면 충분합니다. 아마도 누군가 이것을 개선 할 수 있습니까? 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 자유롭게 개선 / 기여하십시오!


답변

한 가지 접근 방식은 주 객체에서 객체와 기능을 제거하는 것입니다. 그리고 더 간단한 형태를

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


답변

나는 보통 이것을 해결하기 위해 순환 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":"~"}

참고 : Circular-json은 더 이상 사용되지 않으며 이제는 CircularJSON 작성자의 flatted를 사용합니다.

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

에서 : https://www.npmjs.com/package/flatted


답변

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


답변

이것은 관련 답변이 아닐 수도 있지만이 링크 는 JavaScript에서 순환 참조 감지 및 수정 이 순환 종속성을 유발 하는 객체 를 감지하는 데 도움이 될 수 있습니다 .


답변

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