Chrome 101.x中Web Worker内使用Fetch API的请求限制及批量图片获取解决方案问询
Web Worker中批量Fetch图片失败的解决方案
嘿,这个问题我之前处理过类似的大量请求场景,来给你捋捋~
首先,Web Worker本身并没有对Fetch API设置请求数量限制,但你的问题根源在于浏览器的同域名并发请求限制:Chrome(101.x版本)对于HTTP/1.1的请求,默认同域名下最多同时发起6个并发连接;即使是HTTP/2,并发数虽然更高,但也不是无上限的。你一下子发起4000个请求,浏览器会把超出并发数的请求放进队列排队,排队时间太久的请求就会被浏览器主动取消或者超时,这就是为什么你看到无规律的TypeError: Failed to fetch错误——不是URL的问题,是浏览器的限流机制在起作用。
用setTimeout错开请求的方式之所以没用,是因为它只是把请求的发起时间分散了,但如果时间间隔太小,还是会在短时间内涌出大量请求,超过浏览器的并发限制,最终还是会有请求排队超时。
解决思路:控制并发数 + 重试机制
既然你不关注性能,只要求全部成功获取,那核心就是严格控制并发请求的数量,同时给失败的请求加上重试逻辑(应对偶尔的网络波动)。下面是具体的实现方案:
1. 实现带重试的Fetch工具函数
先封装一个支持重试的fetch函数,避免因为临时网络问题导致的请求失败:
// 带重试的fetch函数,默认重试2次 async function fetchWithRetry(url, retryTimes = 2) { try { const response = await fetch(url); // 检查HTTP响应状态,非2xx也视为失败 if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`); } // 根据你的需求返回对应格式,比如blob(图片二进制)或者response.json() return await response.blob(); } catch (error) { if (retryTimes > 0) { console.log(`重试请求:${url},剩余重试次数:${retryTimes}`); // 重试前可以加个短暂延迟,避免立刻重试被服务器限流 await new Promise(resolve => setTimeout(resolve, 500)); return fetchWithRetry(url, retryTimes - 1); } // 重试完毕仍失败,抛出错误 throw new Error(`最终请求失败:${url},原因:${error.message}`); } }
2. 实现并发控制的批量请求函数
接下来写一个控制并发数的函数,确保同时发起的请求数不超过浏览器的并发限制(比如设置为6,和Chrome默认一致):
// 控制并发数的批量fetch函数 async function fetchAllWithConcurrency(urlList, concurrency = 6) { const results = []; // 存储当前正在执行的请求promise const executing = []; // 把二维的URL数组转成一维(因为你的urls是[fI][sI]的二维结构) const flatUrls = urlList.flat(); for (const url of flatUrls) { // 发起单个请求,并处理结果 const requestPromise = fetchWithRetry(url) .then(result => { results.push(result); // 从执行队列中移除已完成的请求 const index = executing.indexOf(requestPromise); if (index !== -1) { executing.splice(index, 1); } }) .catch(error => { // 如果重试后还是失败,可以在这里记录错误,或者根据需求处理 console.error(error.message); // 也可以把错误信息加入results,方便后续排查 results.push({ url, error: error.message }); // 同样从执行队列移除 const index = executing.indexOf(requestPromise); if (index !== -1) { executing.splice(index, 1); } }); executing.push(requestPromise); // 如果当前执行的请求数达到并发限制,等待其中一个完成后再继续 if (executing.length >= concurrency) { await Promise.race(executing); } } // 等待所有剩余的请求完成 await Promise.all(executing); return results; }
3. 修改Web Worker中的onmessage逻辑
最后把原来的代码改成调用上面的并发控制函数:
onmessage = async function(oEvent) { const urls = oEvent.data; // 假设主线程传入的是二维URL数组 try { console.log('开始批量获取图片...'); const allResults = await fetchAllWithConcurrency(urls, 6); // 把结果发送回主线程 postMessage({ type: 'success', data: allResults }); console.log('所有图片获取完成'); } catch (error) { console.error('批量获取图片出错:', error); postMessage({ type: 'error', message: error.message }); } };
额外注意事项
- 服务器限流:如果你的服务器有请求频率限制(比如每分钟最多接受1000个请求),可以在每批请求完成后加个短暂延迟,比如在
await Promise.race(executing);之后加await new Promise(resolve => setTimeout(resolve, 200));,降低请求频率。 - 内存占用:4000张图片的二进制数据会占用不少内存,如果不需要保留所有图片数据,可以在获取后立刻处理(比如转成base64或者发送给主线程后丢弃),避免Web Worker内存溢出。
这样调整后,就能保证所有图片都能成功获取——既不会超出浏览器的并发限制,又能通过重试处理临时的网络问题,完全符合你“只要成功获取所有图片即可”的需求。
内容的提问来源于stack exchange,提问作者futurebaby
相关产品推荐
相关产品推荐

