javascript前端批量下载文件并打包为zip
应用场景
后端提供了下载单个文件的接口,返回数据类型为 blob,现在要在没有额外后端接口的条件下,前端批量下载多个文件并打包生成 zip,供客户下载。
需要安装的依赖与需要前置了解的知识
需要用到 jszip 库,安装
npm install jszip
在 for 循环中使用异步,使所有请求并发,并在最终等所有请求结束后遍历(了解 Promise.all、Promise.allSettled、for await of)
示例
// 引入jszip库
import jszip from "jszip";
const downloadAndZipAll = async () => {
// 创建a标签,用于最终的zip下载
const ele = document.createElement("a");
// 新建zip实例
const zip = new jszip();
// 根据所有文件id请求所有文件blob
// selectedDocument为选中的多个要下载的文件对象
const allPromise = selectedDocuments.map((document) => {
// downloadDocument为根据文件id请求blob数据的Promise函数
return downloadDocument(document.document_id)
.then((res) => {
const blob: Blob = new Blob([res], {
// 定义blob的类型,这里为docx类型
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
// 返回包含文档信息与blob的新对象,文档信息用于后面为文档命名
return { blob, ...document };
// 若请求报错则返回null,用于将文件载入zip时,防止某一请求报错而导致无法生成zip
})
.catch(() => null);
});
// ES8的for await语法,需要在async函数中使用,用于待所有请求有结果后,遍历放入zip文件中
for await (const item of allPromise) {
// 若请求未报错,则返回值不为null,可将文档放入zip包
if (item)
// 将文件放入zip包,第一个参数为文件名,第二个参数为文档的blob数据
zip.file(
`${dayjs(item.make_time, "YYYY-MM-DD HH:mm").format("YYYY-MM-DD")}_${item.product_name}.docx`,
item.blob
);
}
// 除了使用for await语法外还可以使用Promise.all或Promise.allSettled
// Promise.all若有一个请求报错,则Promise.all被中断,进入catch中,但若是在每一个单一请求中已做过错误处理,则不会进入catch
// Promise.allSettled不论请求是否报错,只要响应了,就会返回
for (const item of await Promise.all(allPromise)) {
// 若请求未报错,则返回值不为null,可将文档放入zip包
if (item)
// 将文件放入zip包,第一个参数为文件名,第二个参数为文档的blob数据
zip.file(
`${dayjs(item.make_time, "YYYY-MM-DD HH:mm").format("YYYY-MM-DD")}_${item.product_name}.docx`,
item.blob
);
}
// await所有文件放入zip包后,生成zip的blob,供用户下载
zip.generateAsync({ type: "blob" }).then((content) => {
// 使用blob创建访问链接
ele.href = URL.createObjectURL(content);
// 模拟鼠标点击
ele.click();
// 释放访问链接
URL.revokeObjectURL(ele.href);
});
};
参考资料