JavaScript中使用fs.readFile后数组变为空的问题求助
问题分析与解决方案
问题代码
const fs = require('fs'); var students = []; var programs = []; module.exports.initialize = function(){ return new Promise((resolve, reject) => { fs.readFile('./data/students.json', 'utf8',(err,data)=>{ if(err) reject("Unable to read student data"); students = JSON.parse(data); }); console.log(students); fs.readFile('./data/programs.json', 'utf8',(err,data)=>{ if(err) reject("Unable to read programs data"); programs = JSON.parse(data); }); console.log(programs); resolve("Both data read successfully"); }) }
问题原因
核心是异步执行顺序问题:
fs.readFile是异步非阻塞API,调用后会直接继续执行后续代码,不会等待文件读取完成。- 你在调用
fs.readFile后立刻执行console.log(students)和resolve,这时候文件还没读完,students和programs还是初始的空数组。 - 而
readFile的回调函数是在文件读取完成后才执行的,所以回调内赋值后打印数组会有值,但此时外部的console.log和resolve早就执行完了。
修复方案
使用Promise.all等待两个文件读取操作都完成后,再进行赋值和后续逻辑,同时推荐使用Node.js提供的Promise版fs模块(fs.promises)来简化代码:
方案1:使用fs.promises(推荐)
const fs = require('fs').promises; var students = []; var programs = []; module.exports.initialize = function(){ return Promise.all([ fs.readFile('./data/students.json', 'utf8'), fs.readFile('./data/programs.json', 'utf8') ]) .then(([studentData, programData]) => { students = JSON.parse(studentData); programs = JSON.parse(programData); console.log(students); console.log(programs); return "Both data read successfully"; }) .catch(err => { // 根据错误信息判断是哪个文件读取失败 const errorMsg = err.path.includes('students') ? "Unable to read student data" : "Unable to read programs data"; throw new Error(errorMsg); }); }
方案2:手动封装readFile为Promise
如果不想用fs.promises,可以手动把fs.readFile封装成Promise:
const fs = require('fs'); var students = []; var programs = []; // 封装异步读取为Promise const readFile = (filePath, errorMsg) => { return new Promise((resolve, reject) => { fs.readFile(filePath, 'utf8', (err, data) => { if (err) reject(new Error(errorMsg)); resolve(data); }); }); }; module.exports.initialize = function(){ return Promise.all([ readFile('./data/students.json', "Unable to read student data"), readFile('./data/programs.json', "Unable to read programs data") ]) .then(([studentData, programData]) => { students = JSON.parse(studentData); programs = JSON.parse(programData); console.log(students); console.log(programs); return "Both data read successfully"; }); }
关键说明
Promise.all会等待所有传入的Promise都完成后才进入then回调,确保两个文件的数据都读取完成后再赋值。- 错误处理集中在
catch里,避免了原代码中多次调用reject可能导致的Promise重复拒绝问题。
内容的提问来源于stack exchange,提问作者frowit
相关产品推荐
相关产品推荐

