【问题标题】:JS: handle multiple sequential failed async requestsJS:处理多个顺序失败的异步请求
【发布时间】:2018-03-27 21:48:21
【问题描述】:

我正在使用承诺(带有等待)。我有一个必须等​​待异步请求的异步函数:例如 http 请求。 HTTP 请求可能会失败(超时或其他动机),但我需要调用它直到成功或完成最大尝试次数(比如说 n 次尝试),然后继续执行该函数。 我无法找到一种干净且组织良好的方式来做到这一点。 下面是一个伪代码:

async function func(){
  //DO something before HTTP request
  try{
    let res = await http_request();
  } catch(e){
    //http request failed
    //WHAT TO DO HERE TO CALL AGAIN THE HTTP REQUEST until success??
    //or until max attempts == n?
  }
  //DO other stuff only after the http request succeeded
  return;
}

这个想法是在最后返回一个承诺,如果 http 请求和其余代码成功则解决,或者如果 http 请求尝试失败 n 次或其他错误则拒绝。

PS:http 请求是一个示例,但 http_request() 可以替换为任何其他异步函数。

【问题讨论】:

    标签: javascript promise try-catch


    【解决方案1】:

    你可以做一个while循环,一旦请求成功就会中断,否则再试一次。可以使用计数器来限制尝试次数。

    async function func(){
      let counter = 0;
      while (counter < 100) {
        try{
          let res = await http_request();
          break;
        } catch(e){
          counter++
          continue;
        }
      }
      return;
    }
    

    【讨论】:

    • 我在想花哨的东西,但这可能是最干净和最简单的解决方案 :) 我只需要处理 catch 中的不同错误,并在出现某些故障的情况下继续。
    【解决方案2】:

    你可以再次调用你的函数来重试,你可以给它传递一个重试计数器。您还应该在重试之前插入一个短暂的延迟,以避免重试繁忙的服务器。

    function delay(t, v) {
       return new Promise(resolve => {
           setTimeout(resolve.bind(null, v), t);
       });
    }
    
    const kMaxAttempts = 10;
    const kDelayBeforeRetry = 500;
    
    async function func(cntr = 0){
      //DO something before HTTP request
      ++cntr;
      try{
        let res = await http_request();
        //DO other stuff only after the http request succeeded
        return finalValue;
      } catch(e){
        // test to see if max retries have been exceeded
        // also examine e to see if the error is retryable
        if (cntr > kMaxAttempts || e is not a retryable error) {
            throw e;
        }
        // retry after a short delay
        return delay(kDelayBeforeRetry, cntr).then(func);
    
      }
    }
    

    【讨论】:

      【解决方案3】:

      我会以不同的方式处理请求。你试图只捕获一个错误。您还需要处理失败的响应。无论您使用哪种请求 API,http_request() 很可能会返回一个响应和一个错误对象。您可以使用 response.status === 500 之类的内容检查失败的请求。如果响应因任何原因失败,则可以重试请求。我经常看到它这样做

      http_request.GET(URL).then((response, error) => {
        if (error) // retry
        else if (response.status === 200 && response.body) // success
        else if (response.status === 500) // retry
      })
      

      至于实际代码,您可以创建一个可重用的请求函数,该函数执行 if / else 错误处理并采用 HTTP 方法和一些选项和数据等,并返回您的数据或错误的承诺——这是另一个常见的模式。

      【讨论】:

      • 是的,当然我需要处理不同的响应,只在某些情况下再试一次。
      猜你喜欢
      • 2012-01-15
      • 1970-01-01
      • 2018-05-27
      • 2019-03-26
      • 1970-01-01
      • 1970-01-01
      • 2015-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多