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

JSZip下载Firestore文件夹时压缩包累积包含历史文件问题

问题背景

尝试下载Firestore中指定文件夹内的文件时,基础下载流程可正常运行,但存在两个异常:

  • 遍历每个文件夹生成zip压缩包时,每个下载的压缩包都会累积包含之前文件夹的文件,疑似reduce函数使用方式有误
  • 如果不使用reduce函数,所有下载的压缩包均为空

原实现代码

const DownloadFolders = async () => {
  const jszip = new JSZip();
  const storage = getStorage();

  folderNumber.map(async (num: any) => {
    const folder = await listAll(ref(storage, `/folders/folder${num}`));

    const proms = await folder.items
      .map(async (item: any) => {
        const file = await getMetadata(item);
        const fileRef = ref(storage, item.fullPath);
        const fileBlob = await getDownloadURL(fileRef).then((url) => {
          return fetch(url).then((response) => response.blob());
        });
        jszip.file(file.name, fileBlob);
      })
      .reduce((previousValue, currentValue) => currentValue);

    await proms;
    const blob: any =
      folder.items.length !== 0 &&
      (await jszip.generateAsync({ type: "blob" }));
    FileSaver.saveAs(blob, `folder${rot}.zip`);
  });
};

当前异常表现

  • folder1.zip包含file1
  • folder2.zip同时包含file1和file2
  • 后续压缩包以此类推持续累积之前文件夹的文件

预期效果

  • folder1.zip仅包含file1
  • folder2.zip仅包含file2
  • 每个压缩包仅包含对应文件夹自身的文件
问题根因

代码存在三处核心错误:

  1. JSZip实例声明位置错误:jszip实例在循环外初始化,所有循环共用同一个实例,每次添加的文件都会一直存在于实例中,不会自动清空,直接导致文件跨文件夹累积。
  2. Promise等待逻辑错误:当前写法的reduce只会返回map生成的Promise数组中的最后一个Promise,根本没有等待当前文件夹下所有文件下载完成;如果去掉reduce直接await数组,相当于await一个非Promise值,会直接同步执行后续生成zip的逻辑,此时文件还没下载完,自然生成空压缩包。
  3. 变量名笔误:保存文件时使用了未定义的变量rot,正确的循环变量应为num。
修复方案

修复逻辑如下:

  • 将JSZip实例的初始化移动到循环内部,每个文件夹对应独立的zip实例,从根源避免文件混杂
  • 使用Promise.all()等待当前文件夹下所有文件下载、添加到zip实例完成后,再执行压缩包生成和下载逻辑
  • 修正文件名的变量笔误
  • 替换不适合异步场景的map循环为for...of,避免循环内异步逻辑脱离管控

修复后的完整代码:

const DownloadFolders = async () => {
  const storage = getStorage();

  for (const num of folderNumber) {
    // 每个文件夹单独创建zip实例
    const jszip = new JSZip();
    const folder = await listAll(ref(storage, `/folders/folder${num}`));

    // 空文件夹直接跳过
    if (folder.items.length === 0) continue;

    // 等待当前文件夹所有文件下载并添加到zip
    await Promise.all(
      folder.items.map(async (item) => {
        const file = await getMetadata(item);
        const fileRef = ref(storage, item.fullPath);
        const fileUrl = await getDownloadURL(fileRef);
        const fileBlob = await fetch(fileUrl).then(res => res.blob());
        jszip.file(file.name, fileBlob);
      })
    );

    // 生成压缩包并下载
    const zipBlob = await jszip.generateAsync({ type: "blob" });
    FileSaver.saveAs(zipBlob, `folder${num}.zip`);
  }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 05:54:16