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

Electron异步回调问题:CSV处理完成后无法可靠提示用户

嘿,这个问题我之前做批量文件处理工具时也踩过坑!核心就是异步任务的并发管理没做好——你得确保所有CSV行的逻辑、所有ZIP的复制/删除操作100%完成后,再弹出提示。下面给你具体的解决思路和代码示例:

核心解决方案:用Promise统一管理所有异步任务

同步改异步后,最大的问题就是代码不会自动等待所有异步操作结束。我们需要把所有文件操作包装成Promise,再用Promise.all或者异步循环来追踪所有任务的状态。

1. 先把文件操作封装成Promise

首先把Node.js的fs操作改成Promise版本(直接用fs.promises最方便,不用自己封装回调):

const fs = require('fs').promises;

// 封装复制ZIP的异步函数
const copyZip = async (source, dest) => {
  try {
    // 可以先加文件存在性检查
    await fs.access(source);
    await fs.copyFile(source, dest);
    console.log(`✅ 复制完成: ${dest}`);
  } catch (err) {
    console.error(`❌ 复制失败 ${source}: ${err.message}`);
    // 这里可以收集错误,最后统一提示
    throw err;
  }
};

// 封装删除ZIP的异步函数
const deleteZip = async (filePath) => {
  try {
    await fs.access(filePath);
    await fs.unlink(filePath);
    console.log(`✅ 删除完成: ${filePath}`);
  } catch (err) {
    console.error(`❌ 删除失败 ${filePath}: ${err.message}`);
    throw err;
  }
};

2. 用Promise.all等待所有任务完成

处理CSV每一行时,把对应的异步操作都放进一个Promise数组,最后用await Promise.all()等待所有任务结束:

async function processAllRows(csvRows) {
  const taskList = [];
  const errorList = [];

  // 遍历CSV行,把每个操作加入任务列表
  for (const row of csvRows) {
    // 根据CSV内容判断执行复制还是删除
    let task;
    if (row.operation === 'copy') {
      task = copyZip(row.sourcePath, row.targetPath);
    } else if (row.operation === 'delete') {
      task = deleteZip(row.filePath);
    }

    // 捕获单个任务的错误,避免一个失败导致全部终止
    taskList.push(
      task.catch(err => {
        errorList.push({ row, err: err.message });
      })
    );
  }

  // 等待所有任务(包括失败的)都完成
  await Promise.all(taskList);

  // 所有任务结束后,统一提示用户
  if (errorList.length > 0) {
    // 可以用Electron的dialog展示错误详情
    dialog.showMessageBoxSync({
      type: 'warning',
      title: '操作完成',
      message: `共完成${csvRows.length - errorList.length}个操作,有${errorList.length}个错误`,
      detail: errorList.map(item => `${item.row.romName}: ${item.err}`).join('\n')
    });
  } else {
    dialog.showMessageBoxSync({
      type: 'info',
      title: '操作完成',
      message: '所有ROM操作已全部完成!'
    });
  }
}

3. 配合进度条的进阶优化

如果要同步更新UI进度条,可以在每个任务完成后更新计数器:

async function processWithProgress(csvRows, updateProgressCallback) {
  let completed = 0;
  const total = csvRows.length;
  const errorList = [];

  const taskList = csvRows.map(async (row) => {
    try {
      if (row.operation === 'copy') {
        await copyZip(row.sourcePath, row.targetPath);
      } else {
        await deleteZip(row.filePath);
      }
    } catch (err) {
      errorList.push({ row, err: err.message });
    } finally {
      // 每完成一个任务就更新进度
      completed++;
      updateProgressCallback(completed / total);
    }
  });

  await Promise.all(taskList);
  // 这里再执行完成提示逻辑...
}

在Electron渲染进程里,你可以把进度条的更新函数通过IPC传给主进程,或者主进程完成一步就发IPC通知渲染进程更新。

关键注意点

  • 不要用forEach遍历CSV行:forEach不支持异步等待,会导致所有任务同时触发但无法追踪完成状态,改用for...of或者map生成Promise数组。
  • 单个任务的错误要单独捕获:避免一个文件操作失败导致整个Promise.all终止,用catch收集错误,最后统一展示。
  • Electron主进程和渲染进程通信要可靠:如果提示UI在渲染进程,主进程完成所有任务后用ipcMain.send通知渲染进程,或者用ipcRenderer.invoke做异步调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:05:14