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

无法遍历存储自定义类实例的Map对象问题排查

问题结论

遍历存储自定义类实例的Map不需要任何特殊处理,你遇到的问题和自定义类完全无关,是两个JavaScript常见机制叠加导致的误判:

  • Node/浏览器控制台对引用类型值的懒打印特性
  • 异步流读取的时序错误

为什么会出现Map(0)但展开有6条数据的矛盾

你执行console.log(mgroups)的时刻,mgroups确实是空的,所以控制台第一行会显示Map(0)。
控制台打印对象、Map这类引用类型时,不会在打印瞬间深拷贝快照内容:当你手动点击展开控制台日志条目时,控制台才会去读取该引用指向的内存当前的实际值。这时候异步文件读取已经完成,6条数据都已经写入Map,所以你展开后能看到完整的条目和实例详情。
这也解释了为什么遍历没有任何输出:你写的for...of循环执行时,Map真的是空的,循环体一次都不会进入,自然不会打印任何内容。

异步时序问题的本质

你使用的fs.createReadStream和readline接口都是非阻塞异步API,注册的line、close事件回调不会阻塞后续代码执行。你当前代码的实际执行顺序是:

  1. 调用readObjFile,创建文件读流、注册各类事件回调后,函数直接返回
  2. 紧接着执行你写的Map遍历逻辑,此时文件还在逐行读取过程中,mgroups内没有任何数据,遍历无输出
  3. 文件读取完成,触发close事件回调,所有MaterialGroup实例才被逐一写入mgroups,但此时遍历逻辑早就执行完毕了

修复方案

所有依赖mgroups数据的逻辑,必须等文件读取完成、Map填充完毕后再执行,推荐改造成Promise写法统一异步流程:

const fs = require('fs');
const readline = require('readline');

function readObjFile(objFilePath){
  // 初始化要返回的Map
  const mgroups = new Map();
  return new Promise((resolve, reject) => {
    const objInput = fs.createReadStream(objFilePath);
    const rl = readline.createInterface({
      input: objInput,
      terminal: false
    });

    let mgroup = new MaterialGroup("NotSet");
    // 原有逐行处理逻辑保持不变
    rl.on('line', function(line){
      const pieces = line.split(" ");
      // ... 保留你原有的g/usemtl/f/eof判断和写入mgroups的逻辑
    });

    rl.on('close', () => {
      // 所有行处理完成后,把填充好的Map返回
      resolve(mgroups);
    });

    rl.on('error', err => reject(err));
  })
}

// 调用时等异步读取完成再遍历
async function run() {
  const mgroups = await readObjFile('你的目标obj文件路径');
  // 此时Map已填充完毕,遍历可正常输出
  for(let [key, value] of mgroups){
    console.log('key: ' + key)
    console.log('value: ' + value)
    console.log('value.name: ' + value.name)
  }
}
run();

你可以在遍历前加一句console.log(mgroups.size)快速验证,如果输出为0就完全坐实时序问题,和Map中存储的值类型没有任何关联。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 16:18:20