web前端之封装fetch请求、给fetch添加超时功能、取消请求、AbortController、setTimeout

1,404 阅读4分钟

简易版本

代码

function createRequestWithTimeout(timeout = 3000) {
    return function (url, options) {
        return new Promise((resolve, reject) => {
            const timeoutId = setTimeout(() => {
                reject(new Error("Request timeout"));
            }, timeout);
​
            fetch(url, options)
                .then((response) => {
                    clearTimeout(timeoutId);
                    return response.json();
                })
                .then((response) => {
                    clearTimeout(timeoutId);
                    return resolve(response);
                })
                .catch((error) => {
                    clearTimeout(timeoutId);
                    reject(error);
                });
        });
    };
}
​
const request = createRequestWithTimeout();
​
function handle() {
  request("api/abc/abc", { method: "GET" })
    .then((res) => {
      console.log(res);
    })
    .catch((error) => {
      console.log(error);
    });
}

解析

定义一个名为createRequestWithTimeout的函数,它返回一个新的函数,这个返回的函数用于发起一个带有超时机制的HTTP请求。 1、createRequestWithTimeout函数接收一个可选参数timeout,默认值为3000毫秒(3秒)。参数控制请求的超时时间。 2、返回的函数接收两个参数,url(请求的URL)和options(请求的选项,如请求方法、头部等)。个函数返回一个Promise对象。 3、在返回的函数内部,首先使用setTimeout创建一个定时器,这个定时器会在timeout毫秒后触发。如果在timeout时间内请求没有完成,定时器会调用reject方法,传递一个错误对象,错误信息为"Request timeout"。 4、使用fetch函数发起HTTP请求。fetch函数接收url和options参数。 5、fetch返回的Promisethen方法处理。第一个then处理响应的body,将其转换为JSON格式。如果转换成功,它会调用resolve方法,传递解析后的数据。 6、如果在转换响应体为JSON时发生错误,或者在fetch请求过程中发生错误,catch方法会被调用,它会调用reject方法,传递错误信息。 7、在每个thencatch处理器中,都会调用clearTimeout来清除之前设置的超时定时器。这样做是为了确保在请求成功完成或失败时,不会触发超时错误。 8、handle函数调用request函数发起请求,并处理成功和失败的情况。成功时,它会打印响应数据;失败时,它会打印错误信息。 函数的目的是确保HTTP请求不会无限期地挂起,如果请求在指定的时间内没有完成,就会被中止,并且会通知调用者请求超时。这在处理可能需要较长时间的网络请求时非常有用,可以避免用户界面冻结或资源浪费。


升级版本

代码

function createRequestWithTimeout(timeout = 3000) {
  return function (url, options) {
    return new Promise((resolve, reject) => {
      const abort = new AbortController();
​
      options = options || {};
      if (options.signal)
        options.signal.addEventListener("abort", () => {
          abort.abort();
        });
      options.signal = abort.signal;
      setTimeout(() => {
        reject(new Error("Request timeout"));
        abort.abort();
      }, timeout);
​
      fetch(url, options)
        .then((response) => {
          return response.json();
        })
        .then((data) => {
          return resolve(data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  };
}
​
const request = createRequestWithTimeout();
​
function handle() {
  request("api/abc/abc", { method: "GET" })
    .then((res) => {
      console.log(res);
    })
    .catch((error) => {
      console.log(error);
    });
}

解析

定义一个名为createRequestWithTimeout的函数,它返回一个异步函数,该函数可以发起一个带有超时机制的HTTP请求。 1、createRequestWithTimeout函数接受一个可选参数timeout,默认值为3000毫秒(3秒)。参数定义请求的超时时间。 2、createRequestWithTimeout返回一个函数,该函数接受两个参数,url(请求的URL)和options(请求的选项,如请求方法、头部等)。这个返回的函数返回一个Promise对象。 3、在返回的函数内部,首先创建一个AbortController实例abort。AbortController是一个用于控制一个或多个Web请求的接口,它允许取消这些请求。 4、options参数被检查,如果它已经包含一个signal属性(即一个AbortSignal对象),则为该信号添加一个事件监听器。这个监听器会在signal被中止时调用abort.abort(),从而中止fetch请求。 5、options的signal属性被设置为abort实例的signal属性,这样就可以在超时发生时通过abort.abort()来中止请求。 6、使用setTimeout设置一个定时器,如果在timeout毫秒后请求还没有完成,setTimeout的回调函数会被调用,它会拒绝Promise并中止请求。 7、使用fetch函数发起HTTP请求。fetch函数接受url和options参数。 8、fetch返回的Promisethen方法处理。第一个then处理响应的body,将其转换为JSON格式。如果转换成功,它会调用resolve方法,传递解析后的数据。 9、如果在转换响应体为JSON时发生错误,或者在fetch请求过程中发生错误,catch方法会被调用,它会调用reject方法,传递错误信息。 10、handle函数调用request函数发起请求,并处理成功和失败的情况。成功时,它会打印响应数据;失败时,它会打印错误信息。 createRequestWithTimeout函数的目的是确保HTTP请求不会无限期地挂起。如果请求在指定的时间内没有完成,它会被中止,并且会通知调用者请求超时。这对于防止长时间挂起的请求导致的性能问题非常有用