常规做法是 后端从文件服务器(比如华为云 OBS)读取文件,将这些文件进行打包,然后将压缩包字节流返回给前端,由前端下载到用户本地文件系统。
这种做法有以下几个缺点:
- 文件可能会过大导致超时连接
- 文件经历了两次传输,效率过慢
- 服务器打包,消耗性能
那么我们可以尝试将压力给到前端,这样就只是一个个小的请求,且打包压力在客户端这边,但是也有两个缺点,也比较好解决
- 需要文件服务器配置跨域
- 前端下载文件消耗浏览器内存,可能会造成 OOM(Out of Memory)。
主要是第二个缺点,我们可以通过将文件下载到本地,实时压缩,不用浏览器内存来解决
StreamSaver.js + zip-stream.js 流式下载
/**
* 同步下载打包【推荐】
* @param zipName 压缩包文件名
* @param files 文件列表,格式:[{"name":"文件名", "url":"文件下载地址"},……]
*/
function zipFiles(zipName, files) {
console.log("同步下载打包开始时间:" + new Date());
// 创建压缩文件输出流
const zipFileOutputStream = streamSaver.createWriteStream(zipName);
// 创建下载文件流
const fileIterator = files.values();
const readableZipStream = new ZIP({
async pull(ctrl) {
const fileInfo = fileIterator.next();
if (fileInfo.done) {
//迭代终止
ctrl.close();
} else {
const { name, url } = fileInfo.value;
return fetch(url).then((res) => {
ctrl.enqueue({
name,
stream: () => res.body,
});
});
}
},
});
if (window.WritableStream && readableZipStream.pipeTo) {
// 开始下载
readableZipStream
.pipeTo(zipFileOutputStream)
.then(() => console.log("同步下载打包结束时间:" + new Date()));
}
}