如何绕开浏览器批量下载的限制

如何绕开浏览器批量下载的限制

前言最近遇到一个需求,需要将批量选择的图片,批量一个个下载。

触发单个下载在浏览器中触发下载,我们可以借用 a 元素来触发。

12345678910111213141516const downloadFile = async (url: string, name: string) => { const res = await fetch(url); const blob = await res.blob(); const strList = url.split('.'); const type = strList[strList.length - 1]; const downUrl = window.URL.createObjectURL(blob); const downloadElement = document.createElement('a'); document.body.appendChild(downloadElement); downloadElement.href = downUrl; downloadElement.download = `${name}.${type}`; downloadElement.click(); document.body.removeChild(downloadElement); // 下载完成移除元素 window.URL.revokeObjectURL(downUrl);};

批量触发单个实现了,批量就 promise 来批量执行就好了

12345678910111213141516171819202122232425262728293031323334353637export const batchDownloadFile = async (files: { url: string; name: string; }[], showLoading = true) => { if (showLoading) { // 全局loading,可以忽略 loading.value = ElLoading.service({ lock: true, text: '正在下载中...', background: 'rgba(0, 0, 0, 0.7)', }); } const promiseList = files.map((file) => { return new Promise(async (resolve, reject) => { try { downloadFile(file.url, file.name) resolve(null); } catch { reject('下载错误'); } }); }); const result = await Promise.allSettled(promiseList); if (showLoading) { loading.value?.close(); }// 返回结果 return result.map((item, index) => { return { isSuccess: item.status === 'fulfilled', name: files[index].name, url: files[index].url, }; });};

使用 allSettled 而不用 all 是因为,Promise.all 是有一个被拒绝就会被拒绝,不符合部分成功的情况,所以这里使用的是 allSettled。

浏览器限制对于一次性(即一次宏任务的 event loop)触发下载,浏览器会限制一次触发 a 元素下载最多 10 次。对于下载选择的图片超过 10 张的情况下,要使用分批来下载。

使用 setTimeout 来绕过限制既然一次宏任务限制 10 个,那么就借用 setTimeout 来分批下载即可。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960export const batchDownloadFile = async (files: { url: string; name: string; }[], showLoading = true) => { const batchSize = 10; const delay = 1000; if (showLoading) { loading.value = ElLoading.service({ lock: true, text: '正在下载中...', background: 'rgba(0, 0, 0, 0.7)', }); } const result: { isSuccess: boolean; name: string; url: string; }[] = []; const downloadBatch = async (batch: { url: string; name: string; }[]) => { const promiseList = batch.map((file) => { return new Promise(async (resolve, reject) => { try { await downloadFile(file.url, file.name); resolve(null); } catch { reject('下载错误'); } }); }); const batchResult = await Promise.allSettled(promiseList); batchResult.forEach((item, index) => { result.push({ isSuccess: item.status === 'fulfilled', name: batch[index].name, url: batch[index].url, }); }); }; const delayPromise = (ms: number) => new Promise((resolve) => { setTimeout(resolve, ms); }); // 这里使用递归去执行分批下载 const processBatches = async (remainingFiles: { url: string; name: string; }[]) => { if (remainingFiles.length === 0) { return; } const batch = remainingFiles.slice(0, batchSize); const remaining = remainingFiles.slice(batchSize); await downloadBatch(batch); await delayPromise(delay); await processBatches(remaining); }; await processBatches(files); if (showLoading) { loading.value?.close(); } return result;};

改动后,顺利实现了批量下载超过 10 个文件。

相关推荐

星际战甲ember部件在哪刷
bat365官方登录中文

星际战甲ember部件在哪刷

📅 12-31 👁️ 2396
什么时候才能看到银河?
bat365官方登录中文

什么时候才能看到银河?

📅 09-22 👁️ 4516
‎App Store 上的“豆芽童装
bat365官方登录中文

‎App Store 上的“豆芽童装

📅 08-02 👁️ 5866