Node.js脚本中s3.putObject未执行直接抛错的问题排查
问题产生原因
核心是Node.js的异步非阻塞I/O与事件循环机制导致的执行顺序不符合直觉:
s3.putObject属于异步网络I/O操作,调用该方法时不会同步阻塞等待S3上传流程执行完成,仅仅是把上传任务和对应的回调函数注册到事件队列,就会立刻继续执行当前调用栈内的后续代码。- 你在if分支里的实际执行顺序是:
- 执行
s3.putObject(params, callback),仅注册异步上传任务,未真正启动/完成上传逻辑 - 立刻同步执行下一行的
throw new Error('There were errors'),该错误直接在fs.readFile的回调调用栈中抛出,直接终止整个Node.js进程 - 进程退出后,事件队列里等待调度的S3上传任务根本没有执行机会,自然不会触发实际上传动作。
- 执行
- 注释掉手动抛错的代码后,当前
fs.readFile回调的同步代码会全部执行完、调用栈清空,事件循环才会调度队列里的S3上传任务执行,因此文件可以正常上传。
逻辑验证方法
你可以在代码对应位置加两行日志就能直观看到执行顺序:
if (numberOfErrors > 0) { s3.putObject(params, (err) => { console.log('S3上传回调被触发') // 进程提前终止,该行永远不会打印 if (err) { throw err; } console.log("File uploaded to S3 " + bucket) }) console.log('即将抛出错误终止进程') // 该行会先于所有异步回调打印 throw new Error('There were errors') }
额外注意事项
你当前代码里s3.putObject回调中写的if (err) { throw err; } 同样存在隐患:异步回调里抛出的错误不在原始调用栈中,外层的try/catch无法捕获,会直接触发未捕获异常导致进程崩溃。如果需要等上传完成后再判断是否抛出业务错误,建议将S3操作转为Promise写法,配合async/await控制执行顺序:
// 注意需要给fs.readFile的回调加上async关键字 fs.readFile(filePathName, async (err,data) => { // 省略前面的参数构造逻辑 try { await s3.putObject(params).promise() console.log("File uploaded to S3 " + bucket) if (numberOfErrors > 0) { throw new Error('There were errors') } console.log('There were no errors') } catch(uploadErr) { // 统一处理上传错误、业务错误 console.error('执行异常:', uploadErr) } })
内容的提问来源于stack exchange,提问作者Chi
相关产品推荐
相关产品推荐

