likes
comments
collection

javascript:如何对fetch()请求进行超时处理

作者站长头像
站长
· 阅读数 15

如何对fetch()请求进行超时处理

当开发一个使用网络的应用程序时,首先要记住的规则是不要依赖网络

网络是不可靠的,因为一个HTTP请求或响应可能会因为很多原因而失败。

  • 用户处于离线状态
  • DNS查询失败
  • 服务器没有响应
  • 服务器响应,但出现了错误
  • 以及更多。

用户可以等待8秒来完成简单的请求。这就是为什么你需要对网络请求设置一个超时,并在8秒后通知用户网络问题。

我将向你展示如何使用setTimeout() ,中止控制器,以及fetch() API来进行具有可配置超时时间的请求(包括有趣的演示!)。

1.默认的fetch()超时

默认情况下,fetch() 请求在浏览器指示的时间超时。在Chrome中,网络请求超时为300秒,而在Firefox中为90秒。

async function loadGames() {
  const response = await fetch('/games');
  // fetch() timeouts at 300 seconds in Chrome
  const games = await response.json();
  return games;
}

300秒甚至90秒都远远超过了用户对完成一个简单网络请求的期望。

演示中,/games URL被配置为在301秒内响应。点击加载游戏按钮开始请求,它将在300秒内超时(在Chrome中)。

2.给fetch()请求超时

fetch() API本身不允许以编程方式取消一个请求。为了在所需的时间停止一个请求,你需要另外一个终止控制器

下面的fetchWithTimeout()fetch() 的改进版,它可以创建具有可配置超时的请求。

async function fetchWithTimeout(resource, options = {}) {
  const { timeout = 8000 } = options;
  
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), timeout);
  const response = await fetch(resource, {
    ...options,
    signal: controller.signal  
  });
  clearTimeout(id);
  return response;
}

首先,const { timeout = 8000 } = optionsoptions 对象中提取以毫秒为单位的超时参数(默认为8秒)。

const controller = new AbortController() 创建一个中止控制器的实例。这个控制器可以让你随意停止 的请求。注意,每一个请求都必须创建一个新的中止控制器,换句话说,控制器是不可重复使用的。fetch()

const id = setTimeout(() => controller.abort(), timeout) 启动一个计时功能。在 时间之后,如果计时函数没有被清除, 要中止(或取消)获取请求。timeout controller.abort()

下一行await fetch(resource, { ...option, signal: controller.signal }) ,正确地开始获取请求。注意分配给signal 属性的特殊controller.signal 值:它将fetch() 与中止控制器连接起来。

最后,clearTimeout(id) ,如果请求完成的速度比timeout 的时间快,则清除终止计时功能。

现在,这里是如何使用fetchWithTimeout()

async function loadGames() {
  try {
    const response = await fetchWithTimeout('/games', {
      timeout: 6000
    });
    const games = await response.json();
    return games;
  } catch (error) {
    // Timeouts if the request takes
    // longer than 6 seconds
    console.log(error.name === 'AbortError');
  }
}

fetchWithTimeout() (而不是简单的 )启动一个请求,在fetch() 时间-6秒内取消 timeout

如果对/games 的请求在6秒内还没有完成,那么这个请求就会被取消,并抛出一个超时错误。

你可以在catch 块内使用表达式error.name === 'AbortError' ,以确定是否有请求超时的情况发生。

打开演示,点击加载游戏按钮。对/games 的请求超时,因为它花费的时间超过了6秒。

3.总结

默认情况下,fetch() 的请求在浏览器设置的时间内超时。例如,在Chrome浏览器中,这个设置等于300秒。这比用户期望完成的简单网络请求要长得多。

在进行网络请求时,一个好的方法是配置一个大约8-10秒的请求超时。

如帖子中所示,使用setTimeout() 和中止控制器,你可以创建fetch() 请求,配置为在你愿意的时候超时。

检查浏览器对中止控制器的支持情况,因为截至2020年,它是一项实验性技术。也有一个polyfill

请注意,如果不使用中止控制器,你就没有办法停止fetch() 的请求。不要使用这样的解决方案。