让Fetch()也可以Timeout

字数 425阅读 8034

以前在js中请求网络数据都是使用XMLHttpRequest实现的
Fetch的引入为JavaScript提供了一个更好的替代方法,遗憾的是,fetch没有设置timeOut的设置,这里。。。。
fetch()的详细用法不在这里多说了,不清楚的自行Google

这里记录如何设置请求超时时间

普通的post请求

这是一个普通的POST请求

fetch(url).then((response)=>{
    response.json()
}).then((responseJson)=>{
    console.log(responseJson)
}))

如何设置timeOut?往下看

Promise.race

  • Promise.race接收一个promise对象数组为参数。
  • 只要有一个promise对象进入 Resolved 或者 Rejected 状态的话,就会继续进行后面的处理。
  • 通俗讲就是多个promise“比赛”,谁先跑出结果(成功或失败)就采纳谁

有了Prominse的这个方法就可以有这样的尝试: 在一个新的Promise.race中添加一个TimerPromise,当post请求所在的Promise在timer结束时仍没有返回结果(成功或失败),那么就改变TimerPromise的状态(改为Resolved 或者 Rejected),让Prominse.race收到超时的结果

TimerPromise长这样

let timeoutAction = null;
const timerPromise = new Promise((resolve, reject) => {
    timeoutAction = () => {
      reject('请求超时');
    }
})

使用Promise.race构造新的fetch方法

const _fetch = (requestPromise, timeout=30000) => {
  let timeoutAction = null;
  const timerPromise = new Promise((resolve, reject) => {
    timeoutAction = () => {
      reject('请求超时');
    }
  })
  setTimeout(()=>{
    timeoutAction()
  }, timeout)
  return Promise.race([requestPromise,timerPromise]);
}

requestPromisepost请求的Promise

简单的包装

const post = (params) => {
    const {url,successMsg,body} = params;
    const jsonBody = JSON.stringify(params.body)
    const myFetch = fetch(url,{
        method: 'post',
        headers:{
            "Accept": "application/json",
            "Content-Type" : "application/json"
        },
        body:jsonBody,
   })
   return new Promise((resolve, reject) => {
        _fetch(myFetch, 30000)
        .then(response => {
            return response.json();
        })
        .then(responseData=>{
            resolve(responseData)
        })
        .catch(error=>{
            ToastMessage('网络错误?');
            reject(error);
         });
    });
}
export default post

这种曲线救国的方法有一个弊端:
在到达设定的超时时间仍没有收到fetch的结果时,发出超时的消息,而真正的fetch也许仍在继续,好比设定30s的超时时间,虽然到了30s的时候没有结果会收到超时的消息,但可能就在下一秒(第31s)收到fetch的结果。。。
是不是尴尬。。。
是。。。

推荐阅读更多精彩内容