You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

fs.writeFileSync未将所有变量写入JSON文件的问题排查

问题分析:JSON.stringify输出截断,缺少inturn/outturn属性

问题重现

你编写的Node.js代码如下:

circular = () => { //fix circular stuff for json.stringify
  seen = new WeakSet();
  return (key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) {
        return;
      }
      seen.add(value);
    }
    return value;
  };
};

var gameon = 1;
var fighter1 = {"userid":"97","username":"john","items":{},"ailments":{}};
var fighter2 = {"userid":"91","username":"james","items":{},"ailments":{}};
var resume = 30;

all = {gameon:gameon,fighter1:fighter1,fighter2:fighter2,resume:resume,inturn:fighter1,outturn:fighter2};
    
fs.writeFileSync(file,JSON.stringify(all,circular()),{encoding:'utf8',flag:'w'}); 

预期写入文件的JSON包含gameon、fighter1、fighter2、resume、inturn、outturn所有属性,但实际输出仅到resume就截断,缺少inturn和outturn属性。

原因解析

问题出在你写的circular替换函数上:

  • 函数内部用WeakSet记录了所有已经处理过的对象,而非仅跟踪当前遍历链中的循环引用。
  • 当JSON.stringify处理all对象时:
    1. 处理fighter1和fighter2时,这两个对象会被加入seen集合。
    2. 后续处理inturn(值为fighter1)和outturn(值为fighter2)时,因为seen中已经存在这两个对象,替换函数会返回undefined。
    3. 而JSON.stringify的规则是:如果替换函数返回undefined,对应的属性会被直接忽略,导致这两个属性从输出中消失。

简单说,你的代码误把重复引用(同一个对象被多个属性引用)当成循环引用(对象引用自身或形成遍历闭环)处理了,从而错误过滤了正常的重复引用属性。

修复方案

修改替换函数,只过滤真正的循环引用(即当前遍历栈中已存在的对象),而非所有见过的对象。可以用栈来跟踪当前正在遍历的对象:

const circularReplacer = () => {
  const traversalStack = [];
  return (key, value) => {
    if (typeof value === 'object' && value !== null) {
      // 检查当前对象是否在遍历栈中,判断是否为循环引用
      const stackIndex = traversalStack.indexOf(value);
      if (stackIndex !== -1) {
        // 遇到循环引用,返回undefined跳过
        return;
      }
      // 将当前对象加入遍历栈
      traversalStack.push(value);
      // 利用异步时机在属性处理完成后弹出栈
      process.nextTick(() => traversalStack.pop());
    }
    return value;
  };
};

// 使用修复后的替换函数
fs.writeFileSync(file, JSON.stringify(all, circularReplacer()), { encoding: 'utf8', flag: 'w' });

另外建议给所有变量加上const/let声明,避免全局变量污染:

const gameon = 1;
const fighter1 = {"userid":"97","username":"john","items":{},"ailments":{}};
const fighter2 = {"userid":"91","username":"james","items":{},"ailments":{}};
const resume = 30;

const all = {gameon,fighter1,fighter2,resume,inturn:fighter1,outturn:fighter2};

补充说明

如果你的场景中不存在真正的循环引用(比如fighter1.inturn = fighter1这种情况),其实可以直接去掉替换函数,JSON.stringify本身就能正常处理重复引用,不会报错。只有当存在循环引用时,才需要替换函数来避免Converting circular structure to JSON错误。

内容的提问来源于stack exchange,提问作者Cain Nuke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 03:20:52