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

使用electron-dl下载多个文件时进度条显示异常如何解决?

问题原因

你当前触发的两个下载任务为完全独立的实例,electron-dl的进度回调、完成回调均为单文件维度统计,没有做全局总进度聚合:小体积的svg文件先下载完成时,它的单文件进度100%会直接覆盖全局进度展示,同时它的完成回调会直接把进度重置为0,导致exe的下载进度无法正常展示。

修改方案

主进程(main.ts)修改

给每个下载任务增加唯一标识,进度和完成回调都携带该标识,方便渲染层区分不同任务的状态:

ipcMain.on('download', (event, info) => {
  const taskId = info.taskId
  info.properties.onTotalProgress = (status) =>
    mainWindow.webContents.send('download progress', {taskId, ...status});
  download(BrowserWindow.getFocusedWindow(), info.url, info.properties)
  .then((dl) => mainWindow.webContents.send('download complete', {taskId, savePath: dl.getSavePath()})
  ).catch(console.error);
});

渲染进程(App.tsx)修改

新增全局任务状态管理,聚合所有下载任务的进度计算总进度,等所有任务全部完成后再重置进度:

import { useState, useEffect } from 'react'

// ...其他业务逻辑

/* 新增状态:维护所有下载任务的进度、完成状态 */
const [downloadTasks, setDownloadTasks] = useState<Record<string, {
  total: number,
  transferred: number,
  completed: boolean
}>>({
  'exe-task': { total: 0, transferred: 0, completed: false },
  'svg-task': { total: 0, transferred: 0, completed: false }
})
const [progressNumber, setProgressNumber] = useState(0)

useEffect(() => {
  const downloadPath = path.resolve('/', './exes');
  const downloadPathWindows = `${downloadPath}\\${index}`;
  // 发起exe下载,携带任务ID
  ipcRenderer.send('download', {
    taskId: 'exe-task',
    url: `https://adv.com${book.SmartBookUrl}`,
    properties: {
      directory: downloadPathWindows,
    },
  });
  // 发起svg下载,携带任务ID
  ipcRenderer.send('download', {
    taskId: 'svg-task',
    url: `https://adv.com${book.CoverImageUrl}`,
    properties: {
      directory: downloadPathWindows,
    },
  });

  // 进度事件监听
  const handleProgress = (event, {taskId, total, transferred}) => {
    setDownloadTasks(prev => {
      const newTasks = {
        ...prev,
        [taskId]: { ...prev[taskId], total, transferred }
      }
      // 计算全局总进度
      const allTotal = Object.values(newTasks).reduce((sum, task) => sum + task.total, 0)
      const allTransferred = Object.values(newTasks).reduce((sum, task) => sum + task.transferred, 0)
      const totalPercent = allTotal > 0 ? Math.floor((allTransferred / allTotal) * 100) : 0
      setProgressNumber(totalPercent)
      return newTasks
    })
  }

  // 完成事件监听
  const handleComplete = (event, {taskId}) => {
    setDownloadTasks(prev => {
      const newTasks = {
        ...prev,
        [taskId]: { ...prev[taskId], completed: true }
      }
      // 所有任务完成后再重置进度
      const allCompleted = Object.values(newTasks).every(task => task.completed)
      if (allCompleted) {
        setProgressNumber(0)
        // 可在此处添加全部下载完成后的业务逻辑
      }
      return newTasks
    })
  }

  ipcRenderer.on('download progress', handleProgress)
  ipcRenderer.on('download complete', handleComplete)

  // 组件卸载时移除监听,避免内存泄漏
  return () => {
    ipcRenderer.removeListener('download progress', handleProgress)
    ipcRenderer.removeListener('download complete', handleComplete)
  }
}, [])

补充优化点

如果提前已知两个文件的总大小(如你提到的总大小5MB),可以直接把全局总大小写死为5 * 1024 * 1024,替换进度计算逻辑里的allTotal变量,避免刚下载时仅返回单个文件大小导致的进度跳变问题,展示会更平滑。


内容的提问来源于stack exchange,提问作者Tolga Günaydın

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 03:36:01