You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 19:37:33