【问题标题】:JavaScript/jQuery Promise chainingJavaScript/jQuery Promise 链接
【发布时间】:2015-08-13 09:22:23
【问题描述】:

我真的希望有人能帮助我解决这个问题,尽管我无法(保密问题)分享太多信息。基本上,我编写了这个函数来重试失败的承诺:

function retryOnFailure(func) {
  return func().then(function(resp) {
    return resp
  }, function(err) {
    return setTimeout(function() {
      return retryOnFailure(func)
    }, 5000)
  }
)}

然后我有这段代码可以使用它:

function getStuff() {
  return $.get('/some/endpoint')
}

retryOnFailure(getStuff).then(function(res) { console.log(res) })

现在递归重试函数工作正常,但如果在retryOnFailure 中遇到错误情况,我在最后一行代码中的then 不会触发。我知道原因是因为每个递归调用都会创建一个新的承诺,所以我在最后一行中听到的承诺与得到解决的承诺不同,但我很难弄清楚如何解决这个问题。我希望这个函数是一个通用的重试函数,因此不想处理该方法的实际成功,但我没有看到任何其他方式。任何帮助将不胜感激!

【问题讨论】:

    标签: javascript jquery promise deferred


    【解决方案1】:
    return setTimeout(function() {
        return retryOnFailure(func)
    }, 5000)
    

    看起来您正在尝试做正确的事情 - return 来自您的 .catch 回调的下一个结果。但是,setTimeout 不会返回承诺,因此retryOnFailure() 将立即被解析(带有超时取消 id)。

    相反,您需要确保为您使用的所有异步函数生成一个 Promise,所以让我们从 Promisifying setTimeout 开始:

    function delay(ms) {
      return new Promise(function(resolve, reject) {
        setTimeout(resolve, ms);
      });
    }
    

    现在我们可以使用它在延迟后链接重试,并从中获得承诺:

    function retryOnFailure(func) {
      return func().then(null, function(err) {
        return delay(5000).then(function() {
          return retryOnFailure(func);
        });
      });
    }
    

    请注意,除了.then(null, …),您还可以使用.catch(…)

    【讨论】:

      【解决方案2】:

      这是第一个想到的方法,可能还有更优雅的解决方案:

      function retryOnFailure(func, onSuccess) {
          return func().then(function(resp) {
              onSuccess(resp);
          }, function(err) {
                 return setTimeout(function() {
                     return retryOnFailure(func, onSuccess)
                 }, 5000)
          }
      )}
      
      retryOnFailure(getStuff, function(res) { console.log(res) });
      

      【讨论】:

      • 哦哇...我不知道我怎么会忽略这么简单的解决方案!非常感谢 :) 我真的希望有一些我可以与 then 链接的东西,以便我的团队在整个代码库中保持一致性,但这是一个完全可以接受的解决方案。干杯!
      • return func().then(onSuccess, ...) - 立即更优雅:-)。最里面的回报也是多余的。
      • Errrm... 不是完全避免承诺,而是使用回调,完全不是解决这个问题的方法吗? :) @Bergi 的解决方案,添加基于承诺的延迟,似乎是一个更好的方法。
      • @TrueBlueAussie 正如我所说,我确信有一个更优雅的解决方案,只是分享一种可行的方法。
      • 很多东西工作,但这会完全改变调用代码(回到传统的回调模型)。我只是说这不应该是公认的答案,因为它会引导用户回到非承诺编程的阴暗面,而原来的结果是导致承诺的土地:)。
      【解决方案3】:

      问题是你打电话给setTimeout,它破坏了你的承诺。试试这样的:

      function retryOnFailure(func) {
        return new Promise(function(resolve) {
          func().then(function(resp) {
            resolve(resp);
          }).catch(function(err) {
            setTimeout(function() {
              retryOnFailure(func).then(resolve);
            }, 5000)
          });
        });
      };
      
      retryOnFailure(getStuff).then(function(res) { console.log(res) });
      

      请注意我是如何在函数内部创建了一个新的 Promise,它从不抛出错误,而是简单地尝试处理 func() 并在失败时递归自身。

      设置某种重试限制也是一个好主意。

      祝你好运!

      【讨论】:

      • 避免使用承诺构造函数反模式。
      猜你喜欢
      • 2020-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      • 2015-10-06
      • 2019-01-08
      • 1970-01-01
      相关资源
      最近更新 更多