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

如何在Promise.all的async map调用中终止PDF扫描任务

解决方案

问题核心在于:原代码中最耗时的扫描页面阶段(Promise.all+map)完全没有添加AbortSignal检查,导致点击取消后这些异步任务仍会继续执行;同时后续任务的检查逻辑只是提前返回,没有终止整个Promise链。

1. 在扫描页面的异步任务中添加终止检查并中断Promise链

修改扫描阶段的代码,在每个页面处理前检查信号状态,若已终止则抛出错误并reject整个流程:

setLogs(i18n.t('MAIN_CONTENT.CODESCAN.SUBHEADER.SCAN_STATE.SCANNING'));

try {
  await Promise.all(
    Array.from({ length: pdf._pdfInfo.numPages }).map(async (x, i) => {
      // 每次处理页面前检查是否已取消
      if (abortControllerSignal.aborted) {
        throw new Error('SCAN_ABORTED');
      }
      const cropCordsConfig = await configService.get('ocr-position');
      const cords = {
        x: cropCordsConfig?.x || cropCords.x,
        y: cropCordsConfig?.y || cropCords.y,
        width: cropCordsConfig?.width || cropCords.width,
        height: cropCordsConfig?.height || cropCords.height,
      };
      // 读取图片前再次检查
      if (abortControllerSignal.aborted) {
        throw new Error('SCAN_ABORTED');
      }
      const pageImage = await pdfService.readAsImageData(pdf, i + 1, cords);

      await engine.loadImage(pageImage);
      const text = engine.getText();
      pageCodes.push({
        code: text.replace(/\n/gi, ''),
        pageIndex: i,
      });
      setProgress(parseInt((pageCodes.length / pdf._pdfInfo.numPages) * 100));
    })
  );
} catch (err) {
  if (err.message === 'SCAN_ABORTED') {
    setLogs(i18n.t('MAIN_CONTENT.CODESCAN.SUBHEADER.SCAN_STATE.CANCELLED'));
    setProgress(0);
    reject(err); // 终止整个Promise,不再执行后续逻辑
    return;
  }
  // 处理其他扫描错误
  throw err;
}

2. 给支持AbortSignal的异步方法传递信号

Node.js的fs.promises方法支持接收signal参数,传递AbortSignal后,调用abort时会直接中断文件读取操作:

// 示例:修改文件读取代码
const newExtractedPdf = await pdfService.extractPagesToPdf({
  file: await fs.promises.readFile(pdfPath, { signal: abortControllerSignal }),
  pages: docPages
    .sort(
      (a, b) => parseInt(parseCode(a.code, pageLength).pageNo) - parseInt(parseCode(b.code, pageLength).pageNo)
    )
    .map((p) => ({ originalPageNumber: parseInt(p.pageIndex) + 1 })),
});

3. 优化后续任务的终止逻辑

后续创建PDF的任务中,检查到abort后不仅要返回,还要确保整个Promise链终止。可以将return改为抛出终止错误,统一在外层catch中处理:

const docPromises = Object.keys(documents).map(async (docId) => {
  if (abortControllerSignal.aborted) {
    throw new Error('SCAN_ABORTED');
  }
  // 剩余逻辑不变...
});

try {
  await Promise.all(docPromises);
} catch (err) {
  if (err.message === 'SCAN_ABORTED') {
    setLogs(i18n.t('MAIN_CONTENT.CODESCAN.SUBHEADER.SCAN_STATE.CANCELLED'));
    setProgress(0);
    reject(err);
    return;
  }
  throw err;
}

通过以上修改,就能在点击取消按钮后立即终止所有异步任务,不再继续执行后续的文件读取和处理逻辑。


内容的提问来源于stack exchange,提问作者Qasim Ali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:30:53