Node.js中async调用fs.promises读写文件无报错不生效问题
问题根因
代码无反应的核心原因是混用了两套完全不兼容的Node.js fs异步API,且缺失错误捕获导致报错被静默吞掉:
- 你引入的是
fs.promises下的Promise风格文件方法,这类方法不接收回调函数作为入参,只会返回Promise对象,你传入的read回调永远不会被触发,内部的读写逻辑自然不会执行 - Promise风格API抛出的异常(比如文件不存在、权限不足、文件被占用)必须通过
try/catch或者.catch()捕获,你没有写错误处理,所有报错都被静默吞掉,从外部看就像程序完全没反应 - 额外的逻辑错误:
- 回调内的
content变量没有声明,属于隐式全局变量,严格模式下会直接抛错 - 写文件时传入数字类型的
content,fs会将数字识别为字节长度参数,不会写入你预期的文本内容 - 你在readFile后立刻又调用了一次writeFile写'test',哪怕回调逻辑能正常执行,两个写操作也会产生竞态冲突,反而会导致文件内容错乱
- 回调内的
正确写法
首先是单调用场景下符合Promise异步规范的基础写法:
const fs = require('fs').promises; async function stater(amount){ try { // 读文件指定utf8编码直接拿到字符串内容,不需要传回调 const data = await fs.readFile('stater.txt', 'utf8'); let content = Number(data); content += Number(amount); if(amount === "clear") content = 0; // 写入时要把数字转成字符串,等写入完成后再打日志 await fs.writeFile('stater.txt', String(content)); logger.trace("Stater added: " + amount); } catch (err) { // 首次运行文件不存在时自动初始化 if (err.code === 'ENOENT') { const initVal = amount === "clear" ? '0' : String(amount); await fs.writeFile('stater.txt', initVal); return; } throw err; } } stater(10000);
如果你需要支持每秒多次高频调用,光用上面的写法还会出现竞态问题:多个调用同时进入时会同时读到旧的文件值,计算后互相覆盖写入,最终数值不准。需要加一个简单的串行锁保证所有读写操作按顺序执行:
const fs = require('fs').promises; // 串行执行锁,保证所有stater调用按顺序排队执行 let staterTask = Promise.resolve(); async function stater(amount){ staterTask = staterTask.then(async () => { let content = 0; try { const data = await fs.readFile('stater.txt', 'utf8'); content = Number(data); } catch (err) { if (err.code !== 'ENOENT') throw err; } content += Number(amount); if(amount === "clear") content = 0; await fs.writeFile('stater.txt', String(content)); logger.trace("Stater added: " + amount); }); return staterTask; } // 短时间高频调用也不会出现写覆盖问题 stater(10000); stater(200); stater(50);
内容的提问来源于stack exchange,提问作者mkrdev
相关产品推荐
相关产品推荐

