使用JSZip压缩大量文件时浏览器崩溃问题求助
优化大文件目录压缩上传的解决方案
针对你遇到的内存过载导致浏览器崩溃的问题,核心原因是JSZip默认会将所有文件内容加载到内存中生成完整ZIP Blob,当总容量达到数GB时,内存占用会远超浏览器承载极限。以下是几个实用的优化方案:
方案一:改用流式压缩库+S3分段上传(推荐)
替换JSZip为@zip.js/zip.js,它支持流式压缩——边读取文件、边压缩、边输出数据,无需在内存中存储完整ZIP文件。结合S3的分段上传API,彻底规避内存过载问题。
代码示例:
import { ZipWriter, BlobReader } from "@zip.js/zip.js"; // 1. 初始化S3分段上传,获取uploadId(需调用S3 CreateMultipartUpload API) const uploadId = await initiateS3MultipartUpload("your-bucket", "target-zip.zip"); const parts = []; let partNumber = 1; // 2. 自定义ZipWriter输出流,直接将压缩片段上传到S3 const zipWriter = new ZipWriter({ async writeUint8Array(array) { // 上传当前压缩片段到S3 const partETag = await uploadS3Part( "your-bucket", "target-zip.zip", uploadId, partNumber++, array ); parts.push({ PartNumber: partNumber - 1, ETag: partETag }); // 主动释放内存 array = null; }, async close() { // 完成S3分段上传合并 await completeS3MultipartUpload( "your-bucket", "target-zip.zip", uploadId, parts ); } }); // 3. 逐个处理文件,边读边压缩边上传 for (const file of files) { await zipWriter.add( file.name, new BlobReader(file), { compression: file.type.includes("image/") ? "STORE" : "DEFLATE" } // 图片/视频等已压缩文件直接存储,减少CPU和内存消耗 ); } // 4. 完成压缩与上传 await zipWriter.close();
方案二:优化JSZip内存占用(适合中小规模场景)
如果不想更换库,可以通过分批处理+内存释放缓解压力,但对20GB级内容效果有限:
- 分批加载文件到JSZip,每批生成ZIP片段后立即上传到S3,清空当前批次的内存占用;
- 生成ZIP时启用
streamFiles: true选项(JSZip v3.10+支持),让文件逐个流式写入,而非一次性加载所有内容:
const zip = new JSZip(); const batchSize = 100; // 每批处理100个文件 for (let i = 0; i < files.length; i += batchSize) { const batch = files.slice(i, i + batchSize); batch.forEach(file => zip.file(file.name, file)); // 生成流式ZIP并上传 const stream = await zip.generateAsync({ type: "uint8array", streamFiles: true }); await uploadStreamToS3Chunk(stream, "your-bucket", `temp-part-${i/batchSize}.zip`); // 清空当前批次内存 zip.remove(batch.map(f => f.name)); } // 最后在S3端合并所有临时分片(需调用S3 CopyObject或合并API) await mergeS3Parts("your-bucket", "target-zip.zip", tempPartNames);
方案三:用IndexedDB暂存文件,减少内存占用
将用户上传的文件暂存到IndexedDB而非内存,压缩时逐个读取内容,处理后立即释放:
// 先将文件存入IndexedDB(省略存储逻辑) const zip = new JSZip(); for (const fileMeta of filesMeta) { // 从IndexedDB读取单个文件Blob const fileBlob = await getFileFromIndexedDB(fileMeta.name); zip.file(fileMeta.name, fileBlob); // 释放Blob内存 URL.revokeObjectURL(fileBlob); } // 生成流式ZIP并上传 const stream = await zip.generateAsync({ type: "uint8array", streamFiles: true }); await uploadStreamToS3(stream, "your-bucket", "target-zip.zip");
额外优化点
- 针对已压缩文件(图片、视频、PDF等),关闭ZIP压缩(设置
compression: "STORE"),减少CPU和内存消耗; - 用
performance.memory(Chrome支持)监控内存占用,当接近阈值时暂停处理,避免崩溃; - 所有操作使用异步函数,避免阻塞主线程导致浏览器假死。
内容的提问来源于stack exchange,提问作者Joseph Dry
相关产品推荐
相关产品推荐

