async-await返回Promise触发UnhandledPromiseRejection问题排查
问题原因
代码触发UnhandledPromiseRejectionWarning一共有3个直接问题:
reject调用后没有终止后续逻辑。你在c.cwd回调里触发reject(err)后没有加return,代码会继续执行后续c.get逻辑:Promise一旦被决议,后续的reject/resolve调用都会失效;如果cwd切换失败导致c实例状态异常,c.get大概率返回空值,此时调用stream.once会直接抛出同步TypeError,这个在异步回调里抛出的错误不会被Promise自动捕获,会直接变成全局未处理错误。- 顶层异步逻辑没有最终错误捕获。你在外层自执行async函数的
catch块中又重新throw err,但这个自执行函数本身是顶层入口,没有任何上层逻辑接收这个抛出的错误,其返回的Promise的reject状态没有被处理,直接触发警告。 - 流操作的错误没有被监听。你只监听了stream的
close事件,没有监听可读流、可写流的error事件,流传输过程中出现的网络中断、文件权限不足等错误,不会被现有逻辑捕获,会直接触发未处理异常。
另外你写的return await new Promise(...)是多余写法,async函数直接返回Promise实例即可,额外加await没有实际作用。
修正后代码
const fs = require('fs'); async function getFile(c, sourcePath, fileName, destPath) { return new Promise((resolve, reject) => { c.cwd(sourcePath, function(cwdErr, currentDir) { // 出错后reject直接return,终止后续逻辑执行 if (cwdErr) return reject(cwdErr); c.get(fileName, function(getErr, stream) { if (getErr) return reject(getErr); const writeStream = fs.createWriteStream(destPath); // 统一监听两个流的错误事件,出错直接reject stream.on('error', reject); writeStream.on('error', reject); // 写入完成后再resolve,不要用close事件,避免数据没写完就返回 writeStream.on('finish', resolve); stream.pipe(writeStream); }); }); }); } // 顶层入口必须做最终错误处理 (async function() { try { await getFile(c, '/path/to', 'file.xls', 'file.xls'); console.log('文件获取成功'); } catch (err) { // 不要在顶层catch里继续抛错,直接处理错误即可 console.error('文件获取失败:', err); process.exitCode = 1; } })();
注意事项
- 所有Promise的回调分支中,触发
resolve/reject后如果还有后续逻辑,一定要加return阻断执行,避免出现意外的同步报错或多次决议问题。 - 涉及Node.js流的异步操作,必须同时监听可读端和可写端的
error事件,流的错误不会自动被Promise、async/await语法捕获。 - 程序的顶层异步入口(比如自执行async函数、最外层的异步调用)必须兜底处理所有错误,不要在最外层的catch块中继续向外抛错,此时已经没有上层逻辑可以接收错误。
内容的提问来源于stack exchange,提问作者smarmolena
相关产品推荐
相关产品推荐

