You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

async/await使用问题:pdfData始终为undefined,求排查方案

问题分析与解决方案

嘿,我一眼就看到问题出在哪了——你把回调函数和async/await的用法混在一起了,导致pdfData根本拿不到你想要的结果。

为什么pdfData是undefined?

  1. 当你给toFile传入回调函数时,大多数PDF生成库(比如html-pdf、pdfkit)的toFile方法不会返回Promise,而是直接执行回调。这意味着你写的await其实在等一个根本不是Promise的东西,自然拿不到回调里返回的data。
  2. 回调函数里的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:03:17