自学内容网 自学内容网

Converting circular structure to JSON

最近在项目中遇到了这个问题,头疼,弄了一下午才解决。做一个笔记吧。

1 Converting circular structure to JSON

  • 我这个问题大致就是在使用pinia中出现了循环引用,意思是两个或多个模块、对象或依赖之间形成了相互依赖的链条。
  • 在使用 Pinia 进行状态管理时,遇到 “Converting circular structure to JSON”
    错误通常是因为你试图将一个包含循环引用的对象转换成 JSON。这个错误通常出现在你尝试 JSON.stringify()一个有循环引用的对象时,JavaScript 会抛出这个错误,因为 JSON.stringify() 无法处理循环结构。
TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'kc'
    |     property 'subs' -> object with constructor 'Object'
    --- property 'dep' closes the circle
    at stringify (<anonymous>)
    at y (index-DXHQc27t.js:30:51838)
    at index-DXHQc27t.js:22:2683
    at qa (index-DXHQc27t.js:14:38)
    at kn (index-DXHQc27t.js:14:109)
    at Wc.i.call (index-DXHQc27t.js:14:33736)
    at b (index-DXHQc27t.js:10:15808)
    at qa (index-DXHQc27t.js:14:46)
    at om (index-DXHQc27t.js:14:1835)

2 方法

我们在使用vuex时,肯定需要持久化存储,我这个项目使用了pinia-plugin-persistedstate-2插件,解决防止抛出循环引用

序列化和反序列化 序列化和反序列化允许您自定义持久化和重新水化的状态。

例如,如果您的状态有循环引用,您可能需要使用json-stringify-safe来防止抛出循环引用:

import { createPinia } from "pinia";
import { createPersistedStatePlugin } from "pinia-plugin-persistedstate-2";
import localforage from "localforage";
// https://pinia.vuejs.org/zh
export function useStore(app) {
  // 初始化状态管理
  const pinia = createPinia();
  function safeStringify(obj) {
    const seen = new WeakSet();
    return JSON.stringify(obj, (key, value) => {
      if (typeof value === 'object' && value !== null) {
        if (seen.has(value)) {
          return;  // 发现循环引用时返回 undefined
        }
        seen.add(value);
      }
      return value;
    });
  }
  // 启用持久化插件
  pinia.use(
    createPersistedStatePlugin({
      // storage: localforage,
      serialize: (value) => {
        // 确保返回的是一个序列化的普通对象
        return safeStringify(value);
      },
      deserialize: (value) => {
        // 确保反序列化为普通对象
        return JSON.parse(value);
      },
    })
  );

  // 注册状态管理
  app.use(pinia);
}

用插件防止抛出循环引用问题,会有一些问题,所以直接写了一个方法来防止抛出循环引用。

一. 问题一RangeError: Maximum call stack size exceeded

RangeError: Maximum call stack size exceeded 错误通常发生在 JavaScript 中,当函数出现递归问题或者无限循环时,调用栈超出了其最大限制。调用栈是用于管理函数调用的内存结构,当栈中的调用过多时,就会出现这个错误。

常见原因和解决方法:

  1. 无限递归
    这是最常见的原因。递归函数如果没有正确的退出条件,可能会导致函数不断自我调用,从而使调用栈溢出。
function recursive() {
  recursive();  // 没有退出条件,函数会一直自我调用
}

recursive();

解决方法:
确保递归函数有正确的退出条件(基准情况)。

function recursive(count) {
  if (count > 10) return;  // 基准情况,停止递归
  recursive(count + 1);
}

recursive(0);
  1. 递归深度过深
    即使递归使用得当,如果递归的深度过大,仍然可能导致栈溢出。

解决方法:
如果递归深度很大,考虑使用迭代的方式来替代递归。

function factorial(n) {
  let result = 1;
  for (let i = 1; i <= n; i++) {
    result *= i;
  }
  return result;
}

console.log(factorial(1000));  // 对于大输入,使用迭代
  1. 循环引用
    如果对象之间存在相互引用的关系(循环引用),那么像 JSON.stringify() 这样的操作就可能会在序列化时导致栈溢出错误。
let objA = {};
let objB = { objA };
objA.objB = objB;
JSON.stringify(objA);  // 由于循环引用,会抛出 RangeError

解决方法:
处理循环引用时,可以使用像 flatted 这样的库,或者编写自定义的序列化方法来检测循环引用。

  1. 事件处理器或循环中的无限循环
    在某些情况下,setInterval()、setTimeout() 或事件处理器中的无限循环可能导致栈溢出。

解决方法:
确保在循环或事件处理器中使用了合适的退出条件。

let count = 0;
setInterval(() => {
  count++;
  if (count > 1000) clearInterval(this);  // 设置退出条件
}, 1000);
  1. 深度嵌套的对象
    如果你正在处理深度嵌套的对象或数据结构(如大规模的树形结构或递归数据结构),可能会遇到栈溢出错误。

解决方法:
重新设计数据结构,或者将递归过程改为非递归方式,避免使用过深的递归。

问题二 DOMException: Failed to execute ‘setItem’ on ‘Storage’: Setting the value of ‘app’ exceeded the quota 通常发生在你尝试将过多数据存储到浏览器的 localStorage 或 sessionStorage

  1. localStorage 和 sessionStorage 都有大小限制,通常每个域名下的存储空间大约为
    5MB。当你尝试存储超过这个大小的数据时,就会出现这个错误。

解决方法:

  1. 检查并减少数据大小
  2. 清理存储空间

原文地址:https://blog.csdn.net/qq_48763502/article/details/144427075

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!