使用fs.readFile回调转文件为base64时出现无限循环问题
为什么使用fs.readFile的Promise封装会导致无限循环?
问题核心
你的代码里的致命问题是Promise从未被正确决议(resolve)。在fs.readFile的回调函数中,你最后只是返回了拼接好的base64字符串,但完全没调用resolve()把结果传递给Promise的调用者。这会导致你创建的Promise一直处于pending(挂起)状态,永远不会完成。
如果你的调用方(比如业务逻辑或框架代码)存在等待Promise完成的重试机制(比如循环检测Promise状态),就会触发无限循环——因为Promise永远不会被标记为完成,调用方会一直重试下去。
错误代码的关键问题点
看这段核心代码的问题:
return new Promise((resolve, reject) => { const filePath = "some/path"; fs.readFile(filePath, {encoding: "base64"}, (err, data) => { if (err) { reject(err); return; } // 这里的返回值对Promise毫无意义,必须调用resolve传递结果 return `data:${file.getMimeType()};base64,${data}`; }); });
回调函数的返回值不会被Promise捕获,只有调用resolve()才能把结果传递出去,让Promise进入fulfilled(完成)状态。
正确的Promise封装写法
把回调里的返回操作改成调用resolve:
import fs from 'fs'; @Service() export class FileHandler { public async toBase64(file: MediaFile): Promise<string> { return new Promise((resolve, reject) => { const filePath = "some/path"; fs.readFile(filePath, {encoding: "base64"}, (err, data) => { if (err) { reject(err); return; } // 调用resolve传递最终结果 resolve(`data:${file.getMimeType()};base64,${data}`); }); }); } }
另外,Node.js的fs模块已经提供了Promise化的API,完全不用手动封装,代码会更简洁:
import fs from 'fs/promises'; // 导入Promise版本的fs模块 @Service() export class FileHandler { public async toBase64(file: MediaFile): Promise<string> { const filePath = "some/path"; const data = await fs.readFile(filePath, {encoding: "base64"}); return `data:${file.getMimeType()};base64,${data}`; } }
补充说明
你用readFileSync解决问题是因为同步方法会直接阻塞并返回结果,不会产生挂起的Promise,自然不会触发调用方的重试逻辑。但同步方法会阻塞Node.js的事件循环,在高并发场景下不推荐使用,优先选择Promise化的异步API更合理。
内容的提问来源于stack exchange,提问作者bkrnetic
相关产品推荐
相关产品推荐

