常规做法是 后端从文件服务器(比如华为云 OBS)读取文件,将这些文件进行打包,然后将压缩包字节流返回给前端,由前端下载到用户本地文件系统。

这种做法有以下几个缺点:

  1. 文件可能会过大导致超时连接
  2. 文件经历了两次传输,效率过慢
  3. 服务器打包,消耗性能

那么我们可以尝试将压力给到前端,这样就只是一个个小的请求,且打包压力在客户端这边,但是也有两个缺点,也比较好解决

  1. 需要文件服务器配置跨域
  2. 前端下载文件消耗浏览器内存,可能会造成 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()));
	}
}