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

如何在保留图片加载进度条更新逻辑的同时,使用Promise.all等待所有图片加载完成执行后续操作?

如何在保留图片加载进度条更新逻辑的同时,使用Promise.all等待所有图片加载完成执行后续操作?

我完全理解你的困扰——你既要通过图片的onload事件更新进度条,又要依赖Promise.all等待所有图片加载完成后生成PDF,但现在这两个逻辑因为onload被覆盖而冲突了。别担心,我们只需要调整事件绑定的逻辑,让两者可以共存,下面给你两种可行的解决方案:

问题根源

JavaScript中DOM元素的onload是一个单一函数引用,如果你先后给它赋值不同的函数,后赋值的会直接覆盖前一个。你原来的代码里,先给img.onload绑定了进度条更新的函数,后续Promise.all里又把img.onload替换成了Promise的resolve函数,导致进度条的逻辑被完全丢弃,这就是为什么两者不能同时工作的原因。


方案一:兼容原有代码结构,保留双逻辑

我们可以在创建Promise时,先保存原来的onload函数,在新的onload回调中先执行进度条更新,再resolve Promise,这样就不会覆盖原有逻辑:

// 1. 图片数组初始化与进度条绑定
let images = new Array(pageList.length);
pageList.forEach((e, idx, arr) => {
  let i = new Image;
  i.crossOrigin = "";
  // 保留原有进度条更新逻辑
  i.onload = () => {
    progs[progs.length-1].value += 1;
  };
  i.src = e.url + '&w=1280';
  images[idx] = i;
});

// 2. 修正后的Promise.all逻辑
Promise.all(images.map(img => {
  // 处理图片已经加载完成的边界情况
  if (img.complete) {
    // 补全进度条更新
    progs[progs.length-1].value += 1;
    return Promise.resolve();
  }

  return new Promise(resolve => {
    // 保存原来的进度条更新函数
    const originalOnLoad = img.onload;
    // 新的onload:先执行进度条更新,再resolve Promise
    img.onload = () => {
      if (originalOnLoad) originalOnLoad();
      resolve();
    };
    // 错误情况下也resolve(你也可以选择reject来处理加载失败)
    img.onerror = resolve;
  });
})).then(() => {
  // 后续PDF生成逻辑保持不变
  images.forEach((i) => {
    let dpi = i.height/dimensions[1];
    pdf.addPage([Math.round(i.width/dpi * 100) / 100, dimensions[1]], 'p');
    pdf.addImage(i, 'JPEG', 0, 0, Math.round(i.width/dpi * 100) / 100, dimensions[1]);
  });
})
.then(() => {
  // 这里可以添加PDF保存或者其他后续操作
  // pdf.save('output.pdf');
});

方案二:从一开始就用Promise封装图片加载(更优雅)

这种方式会把图片加载、进度条更新和Promise resolve逻辑完全整合在一起,从根源上避免覆盖问题,代码结构也更清晰,是Promise的最佳实践:

const promises = pageList.map((e) => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = "";
    
    img.onload = () => {
      // 加载完成时同时更新进度条并resolve图片对象
      progs[progs.length-1].value += 1;
      resolve(img);
    };
    
    // 可选:处理图片加载失败的情况
    img.onerror = (err) => {
      console.error(`图片加载失败: ${e.url}`, err);
      reject(err);
    };
    
    img.src = e.url + '&w=1280';
  });
});

// 等待所有图片加载完成
Promise.all(promises)
.then((loadedImages) => {
  // loadedImages就是所有加载成功的图片数组
  loadedImages.forEach((i) => {
    let dpi = i.height/dimensions[1];
    pdf.addPage([Math.round(i.width/dpi * 100) / 100, dimensions[1]], 'p');
    pdf.addImage(i, 'JPEG', 0, 0, Math.round(i.width/dpi * 100) / 100, dimensions[1]);
  });
})
.catch((err) => {
  // 统一处理加载错误
  alert('部分图片加载失败,无法生成PDF');
})
.then(() => {
  // 后续操作,比如保存PDF
  // pdf.save('output.pdf');
});

关键说明

  1. 方案一适合你想尽量保留原有代码结构的场景,核心是通过保存原有onload函数避免覆盖;
  2. 方案二更推荐:把每个异步操作(图片加载)从一开始就封装成Promise,所有相关逻辑(进度条、resolve)都在同一个onload回调中处理,逻辑更集中,也更不容易出错;
  3. 不要忽略错误处理:方案二中添加了onerror的reject逻辑,你可以根据需求决定是忽略失败的图片还是终止流程。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:14:31