场景 - 文件并发下载控制

91 阅读1分钟

为了达到最佳效果,可以结合使用并发控制和分批加载文件的方法。这样既可以限制同时进行的下载任务数量,又可以逐步加载文件,进一步减轻服务器的压力。

1、普通多文件下载

const filesToDownload = [
  { url: 'https://example.com/file1.pdf', name: 'file1.pdf' },
  { url: 'https://example.com/file2.pdf', name: 'file2.pdf' },
  { url: 'https://example.com/file3.pdf', name: 'file3.pdf' }
];

const downloadFile = async (file) => {
  try {
    // 1. 发送 HTTP 请求获取文件数据
    const response = await fetch(file.url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    // 2. 将响应数据转换为 Blob 对象
    const blob = await response.blob();

    // 3. 创建对象 URL
    const url = URL.createObjectURL(blob);

    // 4. 创建隐藏的 <a> 元素并设置属性
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = file.name;

    // 5. 将 <a> 元素添加到文档中
    document.body.appendChild(a);

    // 6. 触发点击事件以启动下载
    a.click();

    // 7. 移除 <a> 元素
    document.body.removeChild(a);

    // 8. 释放对象 URL
    URL.revokeObjectURL(url);

    console.log(`${file.name} 下载完成`);
  } catch (error) {
    console.error(`下载 ${file.name} 失败:`, error);
  }
};

const downloadAllFiles = async () => {
  const promises = filesToDownload.map(downloadFile);
  await Promise.all(promises);
  console.log('所有文件下载完成');
};

downloadAllFiles();

2、文件数量过多,需要控制并发数场景

const axios = require('axios');

const files = Array.from({ length: 1000 }, (_, i) => `file${i}.txt`);
const batchSize = 10; // 每批下载的文件数
const maxConcurrency = 5; // 每批的最大并发数

async function downloadFile(file) {
  const response = await axios.get(`https://example.com/api/download/${file}`);
  // 处理下载的文件
  console.log(`Downloaded ${file}`);
}

async function downloadFilesWithConcurrency(files, maxConcurrency) {
  const pendingPromises = [];

  for (const file of files) {
    const promise = downloadFile(file).then(() => {
      // 从待处理的 Promise 列表中移除已完成的 Promise
      pendingPromises.splice(pendingPromises.indexOf(promise), 1);
    });

    // 将新的 Promise 添加到待处理的 Promise 列表中
    pendingPromises.push(promise);

    // 如果待处理的 Promise 数量达到最大并发数,则等待其中一个完成
    if (pendingPromises.length >= maxConcurrency) {
      await Promise.race(pendingPromises);
    }
  }

  // 等待所有剩余的 Promise 完成
  await Promise.all(pendingPromises);
}

async function downloadFilesInBatches(files, batchSize, maxConcurrency) {
  for (let i = 0; i < files.length; i += batchSize) {
    const batch = files.slice(i, i + batchSize);
    await downloadFilesWithConcurrency(batch, maxConcurrency);
  }
}

downloadFilesInBatches(files, batchSize, maxConcurrency);

总结: 通过结合使用并发控制和分批加载文件的方法,可以更有效地优化大量文件同时下载的情况,减少服务器的压力,提高系统的稳定性和性能。选择合适的策略取决于具体的业务需求和技术栈。