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

jsPDF中添加页面与图片的Promise执行顺序不符问题求助

问题分析与解决方案

问题根源

你的代码中,addPagePromise的Promise构造函数执行器(executor)是同步执行的——只要进入循环的if分支,doc.addPage()会立刻被调用,根本不会等到Promise.all执行。而添加图片的Promise依赖calculateImageWidth这个异步操作,会延后执行,这就导致所有页面添加操作都先于图片处理完成,和你预期的顺序不符。

另外,Promise.all是并行执行所有传入的Promise,它不会保证Promise的执行顺序,只会等待所有Promise完成,这也加剧了顺序混乱的问题。

修复方案

PDF的页面和元素操作是强顺序依赖的,必须串行执行每个步骤(判断是否加页 → 添加对应图片)。可以用Promise链式调用(结合循环累加Promise链)来保证顺序:

修改后的代码示例

// 初始化一个空的Promise链
let operationChain = Promise.resolve();

for (let i = 0; i < usedMonths.length; i++) {
  const currentMonth = usedMonths[i];
  
  operationChain = operationChain.then(() => {
    // 先处理分页逻辑
    if (checkColumnPage(startPos)) {
      doc.addPage();
      // 这里如果需要更新startPos(比如重置到新页面的起始位置),请补充对应逻辑
    }

    // 替换eval,用更安全的方式获取图片变量
    const imgSourceMonth = window[`img_months_${currentMonth}`];
    const clonedStartPos = startPos.slice();

    // 执行图片添加逻辑
    return calculateImageWidth(imgSourceMonth, 20)
      .then(width => {
        doc.addImage(imgSourceMonth, 'PNG', clonedStartPos[0], clonedStartPos[1], width, 20);
        // 这里记得更新startPos,比如根据图片宽度调整下一个元素的位置
      })
      .catch(error => {
        console.error('添加图片失败:', error);
      });
  });
}

// 所有操作完成后,生成或保存PDF
operationChain.then(() => {
  doc.save('your-document.pdf');
});

关键改进点

  1. 串行执行操作:通过Promise链式调用,确保每一轮循环的分页+图片操作都在前一轮完成后执行,严格遵循你预期的顺序。
  2. 移除同步执行的分页Promise:直接在链式调用的then中执行doc.addPage(),不需要额外包裹Promise(因为doc.addPage()是同步方法)。
  3. 替换不安全的eval:用window[变量名]的方式获取全局图片变量,避免eval带来的安全和性能问题。
  4. 明确顺序依赖:每一步操作都等待前一步完成,彻底解决并行执行导致的顺序混乱。

为什么原代码不生效?

  • Promise构造函数的执行器函数是同步触发的:当你创建addPagePromise时,doc.addPage()会立刻执行,和Promise的resolve状态无关。
  • Promise.all是并行执行:所有Promise同时开始执行,分页操作因为是同步的,会瞬间完成,而图片操作因为依赖异步的宽度计算,会延后执行,最终导致分页先于所有图片完成。

内容的提问来源于stack exchange,提问作者Tobias Glaus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 10:37:27