6

Ошибка sendRequest в Chrome: TypeError: Преобразование циклической структуры в JSON

1

Я столкнулся с проблемой в коде, связанном с использованием chrome.extension.sendRequest. У меня есть следующий код:

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

Кто-нибудь имеет представление о том, что вызывает эту ошибку?

5 ответ(ов)

6

Это означает, что объект, который вы передаете в запросе (предполагаю, это pagedoc), имеет циклическую ссылку, что-то вроде следующего:

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

JSON.stringify не может преобразовать такие структуры.

Примечание. Это может быть связано с DOM-узлами, которые имеют циклические ссылки, даже если они не привязаны к дереву DOM. Каждый узел имеет свойство ownerDocument, которое ссылается на document в большинстве случаев. document имеет ссылку на дерево DOM хотя бы через document.body, а document.body.ownerDocument снова ссылается на document, что является только одной из множества циклических ссылок в дереве DOM.

0

Один из подходов заключается в том, чтобы удалить из основного объекта вложенные объекты и функции, оставив только простые значения, а затем преобразовать полученную упрощенную форму в строку. Вот пример функции, которая выполняет это:

function simpleStringify(object) {
  const simpleObject = {};
  for (const 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);
}

Если вы используете Node.js, можно также воспользоваться функцией inspect() из модуля util, чтобы вывести объект в удобном для чтения виде:

import { inspect } from "util";
console.log(inspect(object));

Этот метод более удобен для отладки и визуализации сложных объектов, сохраняя при этом информацию о их структуре.

0

Я обычно использую пакет circular-json из npm для решения этой задачи.

// Пример от Феликса Клинга
var a = {};
a.b = a;
// Загружаем модуль circular-json
var CircularJSON = require('circular-json');
console.log(CircularJSON.stringify(a));
// результат
{"b":"~"}

Обратите внимание: 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"}]

Дополнительную информацию можно найти по следующей ссылке: flatted на npm.

0

Основываясь на ответе 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;
    }
}

// Пример использования

var a = {
    name: "a"
};

var b = {
    name: "b"
};

b.a = a;
a.b = b;

console.log(cleanStringify(a));
console.log(cleanStringify(b));

В этом коде функция cleanStringify проверяет, является ли входной объект действительным объектом. Если да, то она создает его глубокую копию с помощью вспомогательной функции copyWithoutCircularReferences, которая удаляет циклические ссылки, добавляя значения в массив ссылок. Если циклическая ссылка обнаружена, вместо этого добавляется строка ###_Circular_###. В конце, полученный очищенный объект сериализуется в JSON-строку.

0

В вашем случае вы просто забыли использовать async/await при создании маршрута. Попробуйте воспользоваться следующим кодом:

app.get('/products', async (req, res) => {
    const products = await Product.find();
    res.send(products);
});

Обратите внимание на добавление async перед функцией обратного вызова, чтобы корректно использовать await для асинхронного получения данных о продуктах.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь