5

fetch 设置请求超时

在使用 js 自带的 fecth 做网络请求时,没有提供例如$ajax 的超时选项,所以需要自己实现

多个fetch请求在网络不稳定的情况下,会占用大量内存,因为当网速很慢的情况下,fetch会一直等待,直到收到响应

原理

使用Promise.race, Promise.race 的作用是哪个 Promise 先返回结果则最终输出这个 Promise 的返回值

// 超时函数
const timeoutAction = timer => {
  return new Promise(reslove => {
    setTimeout(() => {
      // 实例化超时响应json数据
      const response = new Response(
        JSON.stringify({
          code: 1,
          msg: `timeout ${timer}s`
        })
      );
      return reslove(response);
    }, timer * 1000);
  });
};
const url = "/data.json"; // 请求的url

// 执行,超时控制在0秒,让它永远超时,方便观察
Promise.race([timeoutAction(0), fetch(url)])
  .then(res => {
    return res.json();
  })
  .then(res => {
    if (res.code !== 0) {
      return alert(res.msg);
    } else {
      return console.log(res);
    }
  });

最终实现

上述代码只是让浏览器直到已经超时,而实际上的fetch请求还在继续,所以要多做一步操作, 在超时的时候手动终止fetch请求
AbortController 用于手动终止一个或多个DOM请求,通过该对象的AbortSignal注入的Fetch的请求中。所以需要完美实现timeout功能加上这个就对了

let controller = new AbortController();
let signal = controller.signal;
// 超时函数
const timeoutAction = timer => {
  return new Promise(reslove => {
    setTimeout(() => {
      // 实例化超时响应json数据
      const response = new Response(
        JSON.stringify({
          code: 1,
          msg: `timeout ${timer}s`
        })
      );
      reslove(response);
      controller.abort(); // 发送终止信号
    }, timer * 1000);
  });
};
const url = "/data.json"; // 请求的url

// 执行,超时控制在0秒,让它永远超时,方便观察
Promise.race([
  timeoutAction(0),
  fetch(url, {
    signal: signal //设置信号
  })
])
  .then(res => {
    return res.json();
  })
  .then(res => {
    if (res.code !== 0) {
      return alert(res.msg);
    } else {
      return console.log(res);
    }
  });

目的验证

当看到浏览器异步请求的状态值为canceled时,说明超时拦截成功
canceled

最终代码


zpfei
186 声望7 粉丝

往事如风~


引用和评论

1 篇内容引用
0 条评论