客户反馈无法同时下载 30 个短视频文件的 Zip 压缩包到本地,经排查发现下载文件的总大小超过了 2G,不仅在文件的下载过程中造成了浏览器的卡顿,还在压缩文件时出现缓存区错误
对下载文件的异步任务限流
-
实现原理
可参阅 第 03 期 - 对异步任务并发量进行限流 一文中的优化思路
-
方法封装
const invariable = async ({ data:list = [], limit }, callback) => { window.requestIdleCallback(function(deadline) { const queue = list.splice(0, limit) while(queue.length) { const { url, filename } = queue.shift() fetch(url) .then(response => { const { ok, status, statusText, body: stream } = response if (!ok) { return Promise.reject({ status, statusText }) } else { return stream.getReader() } }) .then(async reader => { const chunks = [] while(true) { const { done, value } = await reader.read() if (!done) { chunks.push(value) } else { callback({ filename, data: new Blob(chunks) }) if (list.length) invariable({ data: list, limit: 1 }, callback) break } } }) .catch(error => console.log(error)) } }, { timeout: 5000 }) }
通过分包实现ZIP文件下载
-
实现原理
设置一定的分组数量,编写分组算法实现多包下载,并给包命名添加序号说明
-
方法封装
import JSZip from 'jszip' const download = ({data, zipName, groupNum = 10}, callback) => { const total = data.length, totalZipPkg = Math.ceil(total / groupNum) let zip = new JSZip(), currentDownloads = 0, serialNumber = 0 invariable({ data, limit: 3, }, ({ filename, data }) => { zip.file(filename, data) currentDownloads += 1 if ((currentDownloads % groupNum === 0) || (currentDownloads % groupNum > 0 && currentDownloads === total)) { zip.generateAsync({ // 压缩等级 1~9,1 压缩速度最快,9 最优压缩方式 type: 'blob', compressionOptions: { level: 9 } }).then(blob => { serialNumber += 1, zipName = zipName || `${new Date().toLocaleString()}.zip` saveAs(blob, `[${serialNumber}-${totalZipPkg}]-${zipName}`) }) zip = new JSZip() } callback(currentDownloads === total ? { done: true } : { type: 'download', done: false, value: currentDownloads }) }) }方法中所引用的
saveAs方法可参阅 第 45 期 - 基于二进制流实现文件下载 一文中的优化思路一起学习,加群交流看 沸点