撬开技术难点!实现Fetch 请求扩展超时功能!

你是否曾经遇到过使用 fetch 请求时无法控制超时时间的尴尬情况?

你是否曾经解决过这个问题,但解决方案却过于局限,缺乏通用性和可重复性?

别担心,今天我就教你一种方法,如何用 AbortController、高阶函数等技术,将原本不具备超时功能的 fetch 进行扩展,实现通用且易复用的超时功能!

阅读本文,跟随子辰一步步解密 fetch 超时功能,通过具体的实现方案和深入的技术分析,带领你解决实际项目中可能遇到的各类问题,让你的技术水平更上一层楼。

撬开技术难点!实现Fetch 请求扩展超时功能!_第1张图片

实现

要实现基本的超时功能其实很简单,只需要使用 AbortController 这个 API,如果你不熟悉它,可以点击链接了解一下。

我们先来看看最简单的代码。

// 首先我们定义一个终止器
const controller = new AbortController();
// 然后调用 fetch 函数,传递一个 url 地址
fetch("https://study.duyiedu.com/api/herolist", {
  // 把终止器的信号传递进来
  signal: controller.signal,
});
// 设置一个 setTimeout 来测试超时终止,为了方便测试,我们这里写 10ms
setTimeout(() => {
  // 终止请求
  controller.abort();
}, 10);

撬开技术难点!实现Fetch 请求扩展超时功能!_第2张图片

可以看到请求已经被取消了。

然后把时间设置成 1000ms 再看看。

撬开技术难点!实现Fetch 请求扩展超时功能!_第3张图片

可以看到数据在 229 毫秒就返回了,并未到超时时间,即使执行终止请求也是无效的。

但是这个代码呢,虽然能够实现超时功能,却没有任何通用性和可复用性。

如果我们以后还想要使用超时功能,就必须把这段代码重复写一遍。

那么我们就应该把它封装成一个通用的 request 函数。

/**
 * @description: 封装一个请求函数
 * @param {*} timeout: 传入超时时间
 */
function request(timeout) {
  const controller = new AbortController();
  fetch("url", {
    signal: controller.signal,
  });
  setTimeout(() => {
    controller.abort();
  }, timeout);
}

但是这样一来呢,我们就会发现,事情变得更加复杂了。

我们本来只想要处理超时问题,结果却变成了要封装 Ajax。

还要考虑很多其他的问题,比如 url 地址要不要传,fetch 的配置要不要传等等。

所以我们在进行封装的时候就必须考虑,要保持 fetch 的功能不变,不能把 fetch 封装一遍。那样就是小题大做了。

我们希望的是在使用 request 函数的时候,跟使用 fetch 是一样的。

那么这里呢就会让我们想到一个库,叫做 MockJS,做前端开发的同学肯定都知道这个库,它可以拦截 Ajax 请求,并返回模拟数据。

那么它是怎么做到的呢?我们分析一下源码就知道了,其实很简单。

// 拿到原来的 XHR
const oldXHR = XMLHttpRequest;
// 然后给 XHR 重新赋值
window.XMLHttpRequest = function () {
  // 在这个新的函数里做一些别的事情
  // 有可能还会调用原来的 XHR
  new oldXHR();
};

这样做也是一种办法,但是它有侵入性,这样一弄整个系统中所有的 fetch 函数都被改了。

有些 fetch 函数不想使用超时功能或者模拟数据的时候就没办法了。

所以这种方案虽然给了我们一些提示,但是也不是很好。

因为我们要既没有侵入性又有通用性,我们就可以利用高阶函数的方式来处理。

/**
 * @description: 创建一个 fetch 函数
 * @param {*} timeout: 传入超时的时间
 * @return {*} 返回一个新的 fetch 函数
 */
function createFetch(timeout) {
  // 返回一个新的 fetch 函数
  return (resource, options) => {
    // 定义一个终止器
    let controller = new AbortController();
    // options 配置默认值
    options = options || {};
    // 向原来的 fetch 配置中加入 signal
    options.signal = controller.signal;
    setTimeout(() => {
      // 当时间到达之后运行 abort
      controller.abort();
    }, timeout);
    return fetch(resource, options);
  };
}

// 如果我们不想使用超时功能就可以直接使用 fetch
fetch();

// 如果我们想要使用超时功能就使用 createFetch 创建一个新的 fetch
createFetch(3000)("url", {});

我们还是使用之前的 url 测试一下效果。

createFetch(10)("https://study.duyiedu.com/api/herolist");
createFetch(1000)("https://study.duyiedu.com/api/herolist");

撬开技术难点!实现Fetch 请求扩展超时功能!_第4张图片 撬开技术难点!实现Fetch 请求扩展超时功能!_第5张图片可以看到都是没问题。

撬开技术难点!实现Fetch 请求扩展超时功能!_第6张图片

 而且我们可以看到,超时之后是一个拒绝的 Promise,依然可以做后续的处理。

总结

通过本文,我们学习了如何给 fetch 添加超时功能,并且保持了 fetch 的原有功能和通用性,同时我们还分析了 MockJS 的源码。

对源码的分析不仅让同学们对这个技术本身有了新的认识,还可以为将来的开发提供很多启发和灵感。

所以经常看优质的代码才能提高自己代码质量。

你可能感兴趣的:(前端,java,开发语言)