async/await使用问题:pdfData始终为undefined,求排查方案
问题分析与解决方案
嘿,我一眼就看到问题出在哪了——你把回调函数和async/await的用法混在一起了,导致pdfData根本拿不到你想要的结果。
为什么pdfData是undefined?
- 当你给
toFile传入回调函数时,大多数PDF生成库(比如html-pdf、pdfkit)的toFile方法不会返回Promise,而是直接执行回调。这意味着你写的await其实在等一个根本不是Promise的东西,自然拿不到回调里返回的data。 - 回调函数里的
return data也不会传递到外部——回调是一个独立的执行上下文,它的返回值和外部的pdfData半毛钱关系都没有。
怎么修正?
核心思路是把整个流程都用Promise/await来统一管理,抛弃回调嵌套。下面是两种可行的写法:
写法1:把toFile包装成Promise(通用方案,适配所有带回调的库)
先把toFile的回调逻辑包装成Promise,这样就能用await等待文件生成完成:
// 先封装一个生成PDF的Promise函数 const generatePdfToFile = (content, options, fileName) => { return new Promise((resolve, reject) => { pdf.create(content, options) .toFile(`./src/services/temp/${fileName}`, (error, result) => { if (error) { console.error("生成PDF失败:", error); reject(error); } else { resolve(result.filename); // 把生成的文件路径传给后续流程 } }); }); }; // 主流程用async/await串联所有步骤 const processPdfUpload = async () => { try { // 第一步:生成PDF文件 const tempFile = await generatePdfToFile(content, options, fileName); // 第二步:获取S3签名 const awsSign = await signS3(`statements/${fileName}`, "application/pdf"); // 第三步:上传到S3 const uploadStatus = await uploadDocumentToS3(awsSign, tempFile); // 第四步:删除临时文件(用fs.promises的Promise版本,避免回调) try { await fs.promises.unlink(tempFile); console.log("临时文件已成功删除"); } catch (err) { console.error("删除临时文件失败:", err); // 这里可以选择是否抛出错误——如果删除失败不影响上传结果,就不用中断流程 } // 最后返回你需要的数据 const pdfData = { status: uploadStatus, url: awsSign.url }; console.log(pdfData); return pdfData; } catch (err) { console.error("整个流程出错:", err); // 统一处理错误,比如返回错误状态 return { status: "error", message: err.message }; } }; // 调用执行流程 processPdfUpload();
写法2:直接用库的Promise版本(如果支持的话)
很多现代的PDF库已经支持Promise调用了——只要你不给toFile传回调函数,它就会返回一个Promise。比如html-pdf就支持这种写法,代码会更简洁:
const processPdfUpload = async () => { try { // 直接await toFile的Promise返回值 const result = await pdf.create(content, options).toFile(`./src/services/temp/${fileName}`); const tempFile = result.filename; // 后续步骤和上面一样 const awsSign = await signS3(`statements/${fileName}`, "application/pdf"); const uploadStatus = await uploadDocumentToS3(awsSign, tempFile); await fs.promises.unlink(tempFile); const pdfData = { status: uploadStatus, url: awsSign.url }; console.log(pdfData); return pdfData; } catch (err) { console.error("流程出错:", err); return { status: "error", message: err.message }; } }; processPdfUpload();
关键要点总结
- 永远不要把回调函数和async/await混着用,不然异步流程的控制权会乱掉。
- 所有异步操作都要用await等待,确保步骤按顺序执行(生成PDF→签名→上传→删文件)。
- 用
fs.promises.unlink替代回调版的fs.unlink,保持代码风格统一,也更容易处理错误。
内容的提问来源于stack exchange,提问作者Markus Hayner
相关产品推荐
相关产品推荐

