将CSV行作为Node.js对象键后,无法在回调外访问对象的问题
问题描述
我需要在Node.js中创建一个映射对象,将CSV文件里participant_membership_id列的所有ID作为键,对应值统一设为0(期望格式:{ ID值: 0, ... })。CSV仅包含该列和一系列ID。
我用fs.createReadStream结合csv-parser写了处理代码,在end事件回调内能成功生成目标对象cardinality_mapping并打印正确结果,但在回调外访问该对象时,却显示对象未被正确赋值。
完整代码如下:
const { DateTime } = require("luxon") const _ = require("lodash") const { db } = require("./firebase") const fs = require("fs") const csv = require("csv-parser") const csv_ids = [] let cardinality_mapping = {} fs.createReadStream("./data/participant__memberships_ids_mysql.csv") .pipe(csv()) .on("data", (data) => { csv_ids.push(data) }) .on("end",()=>{ const cardinality_mapping = {} for (const row of csv_ids) { const keys = Object.values(row) cardinality_mapping[keys[0]] = 0 } console.log(cardinality_mapping) }) console.log(cardinality_mapping)
错误原因与修复方案
你的代码有两个核心问题:
1. 异步执行顺序问题
fs.createReadStream是异步操作,代码会先执行回调外的console.log(cardinality_mapping),此时CSV文件还没读完,end回调里的赋值逻辑根本没运行,所以打印的是初始的空对象{}。
2. 变量作用域冲突
在end回调里,你用const重新声明了cardinality_mapping,这会在回调的局部作用域里创建一个新变量,完全和外部的let cardinality_mapping = {}没关系——相当于你修改的是另一个变量,外部的全局变量根本没被更新。
修复后的代码
const { DateTime } = require("luxon") const _ = require("lodash") const { db } = require("./firebase") const fs = require("fs") const csv = require("csv-parser") const csv_ids = [] let cardinality_mapping = {} fs.createReadStream("./data/participant__memberships_ids_mysql.csv") .pipe(csv()) .on("data", (data) => { csv_ids.push(data) }) .on("end",()=>{ // 去掉const,直接使用外部声明的变量 cardinality_mapping = {} for (const row of csv_ids) { const keys = Object.values(row) cardinality_mapping[keys[0]] = 0 } console.log("回调内的映射对象:", cardinality_mapping) // 所有需要用到这个映射的逻辑,都要放在这个回调里,或者用Promise包装后用async/await useMapping(cardinality_mapping) }) // 封装需要使用映射的逻辑 function useMapping(mapping) { console.log("外部函数中访问映射:", mapping) // 这里写后续需要处理的逻辑,比如写入数据库、其他计算等 }
额外优化:避免全局变量(可选)
如果不想用全局变量,可以用Promise封装读取逻辑,用async/await让代码更直观:
const { DateTime } = require("luxon") const _ = require("lodash") const { db } = require("./firebase") const fs = require("fs") const csv = require("csv-parser") async function createCardinalityMapping() { return new Promise((resolve) => { const csv_ids = [] fs.createReadStream("./data/participant__memberships_ids_mysql.csv") .pipe(csv()) .on("data", (data) => csv_ids.push(data)) .on("end", () => { const mapping = {} for (const row of csv_ids) { const keys = Object.values(row) mapping[keys[0]] = 0 } resolve(mapping) }) }) } // 使用时 async function main() { const cardinality_mapping = await createCardinalityMapping() console.log(cardinality_mapping) // 后续逻辑直接在这里写 } main()
内容的提问来源于stack exchange,提问作者SAR_90
相关产品推荐
相关产品推荐

