【问题标题】:How can I use setTimeout to break a fetch request in react native?我如何使用 setTimeout 在本机反应中中断获取请求?
【发布时间】:2026-01-03 07:50:02
【问题描述】:

我正在尝试通过获取请求从服务器获取一些数据。 有时网络会出现故障或发生类似的其他事情,我希望有一个超时以防止进一步的错误并获得更好的体验。

实际上我想等待 20 秒,如果没有得到任何响应,我想显示错误并中断获取请求。

我有一个加载模式,我可以通过超时关闭它,但我也想中断获取请求。

这是我的获取请求代码:

_testPress = async () => { 
        //setTimeout(() => {this.setState({loading: false})}, 20000)
        this.setState({loading : true})
        fetch(getInitUrl('loginUser'), {
        method: 'POST',
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({          
          password : this.state.password,
          email : this.state.emailAddress,            
        }),
      }).then(response => Promise.all([response.ok, response.status ,response.json()]))
      .then(([responseOk,responseStatus, body]) => {        
        if (responseOk) {
          //console.log(responseOk, body);
          this._signInAsync(body.token);
          // handle success case
        } else {
          console.log(responseStatus);
          this.setState({
            showAlert : true,
            alertType : true,
            alertMessage : body.message
          });
        }
      })
      .catch(error => {
        console.error(error);
        // catches error case and if fetch itself rejects
      });
      }

我使用 setTimeout 关闭加载模块,但它不会停止我希望它在 20 秒后停止的实际请求。

请帮助我提供您的建议。 谢谢。

【问题讨论】:

标签: react-native


【解决方案1】:

没有可以添加到fetch 的标准参数,但您可以解决此问题:

// creating a wrapper for promises
function timeout(milliseconds, promise) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("timeout exceeded"))
    }, milliseconds)
    promise.then(resolve, reject)
  })
}

// using that wrapper with fetch
timeout(1000, fetch('/api'))
  .then(function(response) {
     // response success
}).catch(function(error) {
  // timeout error or server error
})

示例:

超时:

// creating a wrapper for promises
function timeout(milliseconds, promise) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error("timeout exceeded"))
        }, milliseconds);

        promise.then(resolve, reject);
    });
}
  
const requestErr = new Promise((resolve, reject) => {
    setTimeout(() => {
        // request finished.
        resolve();
    }, 2500);
})

timeout(1000, requestErr)
    .then(function(response) {
        console.log("OK!");
    }).catch(function(error) {
        console.log("ERROR TIMEOUT!");
    });

未超过超时:

// creating a wrapper for promises
function timeout(milliseconds, promise) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error("timeout exceeded"))
        }, milliseconds);

        promise.then(resolve, reject);
    });
}

const requestOk = new Promise((resolve, reject) => {
    setTimeout(() => {
        // request finished.
        resolve();
    }, 500);
})

timeout(1000, requestOk)
    .then(function(response) {
        console.log("OK!");
    }).catch(function(error) {
        console.log("ERROR TIMEOUT!");
    });

您也可以使用有自己的超时设置的AXIOS

【讨论】:

    【解决方案2】:

    您可以通过将“信号”传递给获取选项来中止获取请求。

    一个 AbortSignal 对象实例;允许您与获取请求进行通信,并在需要时通过 AbortController 中止它。

    https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch

    完整的代码示例在这里。

    https://javascript.info/fetch-abort

    let controller = new AbortController();
    fetch(url, {
      signal: controller.signal
    });
    
    controller.abort();
    

    【讨论】:

      【解决方案3】:

      Fetch 没有实现连接超时。您也不能中止获取请求。

      看看这个 gist,它在 fetch 请求周围包裹了一个 Promise.race。只要其中一个承诺(获取或超时)解决或拒绝,承诺就会解决:
      https://gist.github.com/davej/728b20518632d97eef1e5a13bf0d05c7

      这样的事情应该可以工作:

      Promise.race([
        fetch(getInitUrl('loginUser'), *...fetchparams* ), 
        new Promise((_, reject) =>
          setTimeout(() => reject(new Error('Timeout')), 7000)
        )
      ]).then(*stuff*).catch(*stuff*)
      

      或者,你也可以试试 axios,一个 fetch 的替代方案,支持超时: https://github.com/axios/axios

      【讨论】:

      • 我试过你的建议,它奏效了。但正如我提到的,我已经使用了 setTimeout 并且它确实有效,但它并没有停止获取请求。而且您的解决方案也没有阻止该请求。所以你能告诉我你的解决方案和我的函数中的简单 setTimeout(() => {this.setState({loading: false})}, 20000) 的区别吗?
      • 很遗憾,您无法停止获取请求。如果您真的需要在超时后中止您的请求,则必须查看另一个 HTTP 库(如 axios)。在我的 Promise.race 示例中,请求仍然通过。但是,如果我没记错的话,如果稍后失败,它不应该再抛出错误。
      • 我可以用 axios 做 react native 吗?