You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Angular 11中使用JSZip与FileSaver动态生成含多文件Zip包的问题

解决JSZip结合异步API生成Zip包时文件为空的问题

我完全懂你遇到的困扰——用JSZip打包从服务端异步获取的文件时,总是出现txt文件夹为空的情况,而硬编码内容就正常。这核心问题就是异步操作的执行顺序:你原来的代码里,zip.generateAsync()在所有文件的下载请求完成前就已经执行了,这时候还没来得及把下载到的文件添加到Zip里,自然生成的包就只有readme.txt。

错误原因拆解

  • 硬编码base64时,所有文件添加操作都是同步的,循环跑完后Zip里已经有了所有文件,再生成Zip自然没问题。
  • 但调用downloadService.downloadFile()是异步的(返回Observable),你的forEach循环只是发起了所有请求,并没有等待它们完成就直接执行了zip.generateAsync(),这时候txt文件夹里还没有任何异步获取到的文件。
  • 你后来把生成Zip的逻辑放到循环里,每个请求完成就生成一次Zip,所以最后一个请求完成时,之前的文件已经都添加好了,这时候生成的Zip是完整的,但前面的请求完成时生成的Zip都是不完整的,所以会出现多个Zip包。

正确解决方案

我们需要先等待所有文件的异步请求都完成并把文件添加到Zip后,再生成并下载Zip。这里可以用Promise.all()来统一等待所有异步操作完成,同时把Angular的Observable转换成Promise来适配。

完整的TypeScript代码示例:

import { lastValueFrom } from 'rxjs'; // 导入rxjs的工具方法,把Observable转成Promise

// 初始化Zip实例和文件夹
const zip = new JSZip();
zip.file("readme.txt", "Files required");
const txtFolder = zip.folder("txt");

// 先判断selectedItems是否存在,避免空指针
if (!this.selectedItems) {
  console.warn("没有选中需要打包的文件");
  return;
}

// 把每个文件的下载+添加操作转换成Promise
const downloadAndAddPromises = this.selectedItems.map(async (item) => {
  // 将Observable转为Promise,等待请求完成
  const response = await lastValueFrom(this.downloadService.downloadFile(item.name));
  const base64Content = response.output.split(",")[1];
  // 把下载到的文件添加到Zip文件夹中
  txtFolder.file(item.name, base64Content, { base64: true });
});

// 等待所有文件都下载并添加完成后,再生成Zip包
Promise.all(downloadAndAddPromises)
  .then(() => zip.generateAsync({ type: "blob" }))
  .then((zipBlob) => {
    FileSaver.saveAs(zipBlob, this.fileZipName);
  })
  .catch((error) => {
    console.error("打包或下载过程出错:", error);
    // 这里可以添加用户友好的错误提示,比如弹窗告知打包失败
  });

代码关键点说明

  • lastValueFrom:Angular的Observable可以通过这个方法转换成Promise,让我们能使用awaitPromise.all来等待异步操作完成(Angular旧版本也可以用toPromise(),但lastValueFrom是官方推荐的新方法)。
  • Array.map():把每个选中的文件转换成一个独立的Promise,每个Promise对应一次文件下载和Zip添加操作。
  • Promise.all():只有当所有传入的Promise都成功完成后,才会执行后续的Zip生成和下载逻辑,确保此时所有文件都已经添加到Zip中。
  • 错误捕获:添加catch块可以捕获下载失败、Zip生成失败等异常,方便调试和给用户反馈。

额外提示

如果需要打包的文件数量较多,建议在页面上添加加载状态提示(比如“正在打包文件,请稍候”),提升用户体验。

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

火山引擎 最新活动