首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >承诺重试设计模式

承诺重试设计模式
EN

Stack Overflow用户
提问于 2016-07-05 22:11:52
回答 20查看 116.8K关注 0票数 109

编辑

  1. 持续重试直到承诺解决为止的模式(使用delaymaxRetries)。
  2. 持续重试直到条件在结果上满足为止的模式(使用delaymaxRetries)。
  3. 具有无限重试的有效内存动态模式(delay提供)。

代码的#1.继续重试,直到承诺解决(对语言的任何改进社区等?)

代码语言:javascript
复制
Promise.retry = function(fn, times, delay) {
    return new Promise(function(resolve, reject){
        var error;
        var attempt = function() {
            if (times == 0) {
                reject(error);
            } else {
                fn().then(resolve)
                    .catch(function(e){
                        times--;
                        error = e;
                        setTimeout(function(){attempt()}, delay);
                    });
            }
        };
        attempt();
    });
};

使用

代码语言:javascript
复制
work.getStatus()
    .then(function(result){ //retry, some glitch in the system
        return Promise.retry(work.unpublish.bind(work, result), 10, 2000);
    })
    .then(function(){console.log('done')})
    .catch(console.error);

代码的#2继续重试,直到一个条件满足在then上的结果,以可重用的方式(条件是什么将改变)。

代码语言:javascript
复制
work.publish()
    .then(function(result){
        return new Promise(function(resolve, reject){
            var intervalId = setInterval(function(){
                work.requestStatus(result).then(function(result2){
                    switch(result2.status) {
                        case "progress": break; //do nothing
                        case "success": clearInterval(intervalId); resolve(result2); break;
                        case "failure": clearInterval(intervalId); reject(result2); break;
                    }
                }).catch(function(error){clearInterval(intervalId); reject(error)});
            }, 1000);
        });
    })
    .then(function(){console.log('done')})
    .catch(console.error);
EN

回答 20

Stack Overflow用户

回答已采纳

发布于 2016-07-06 13:15:22

有点不同的东西..。

异步重试可以通过构建.catch()链来实现,而不是通常的.then()链。

这一办法是:

  • 只有在指定的最大尝试次数下才有可能。(链条必须长度有限),
  • 只建议有一个较低的最大值。(许诺链消耗的内存与其长度大致成正比)。

否则,使用递归解决方案。

首先,将实用程序函数用作.catch()回调。

代码语言:javascript
复制
var t = 500;

function rejectDelay(reason) {
    return new Promise(function(resolve, reject) {
        setTimeout(reject.bind(null, reason), t); 
    });
}

现在,您可以非常简洁地构建.catch链:

1.重试直到承诺解除,并延迟

代码语言:javascript
复制
var max = 5;
var p = Promise.reject();

for(var i=0; i<max; i++) {
    p = p.catch(attempt).catch(rejectDelay);
}
p = p.then(processResult).catch(errorHandler);

演示https://jsfiddle.net/duL0qjqe/

2.不加延迟地重试直到结果满足某些条件,

代码语言:javascript
复制
var max = 5;
var p = Promise.reject();

for(var i=0; i<max; i++) {
    p = p.catch(attempt).then(test);
}
p = p.then(processResult).catch(errorHandler);

演示https://jsfiddle.net/duL0qjqe/1/

3.重试直到结果满足某些条件,并延迟

在考虑了(1)和(2)之后,合并的test+delay同样是微不足道的。

代码语言:javascript
复制
var max = 5;
var p = Promise.reject();

for(var i=0; i<max; i++) {
    p = p.catch(attempt).then(test).catch(rejectDelay);
    // Don't be tempted to simplify this to `p.catch(attempt).then(test, rejectDelay)`. Test failures would not be caught.
}
p = p.then(processResult).catch(errorHandler);

test()可以是同步的或异步的。

添加更多的测试也是微不足道的。只要在两条鱼之间夹上一条链子就行了。

代码语言:javascript
复制
p = p.catch(attempt).then(test1).then(test2).then(test3).catch(rejectDelay);

演示https://jsfiddle.net/duL0qjqe/3/

所有版本都是为attempt设计的,是一个承诺返回的异步函数。它还可以返回一个值,在这种情况下,链将遵循其成功路径到达下一个/终端.then()

票数 88
EN

Stack Overflow用户

发布于 2017-06-15 21:09:28

2.持续重试直到条件在结果上满足为止的模式(带有延迟和maxRetries)

这是一种很好的方法,可以通过递归的方式使用本机承诺来实现这一点:

代码语言:javascript
复制
const wait = ms => new Promise(r => setTimeout(r, ms));

const retryOperation = (operation, delay, retries) => new Promise((resolve, reject) => {
  return operation()
    .then(resolve)
    .catch((reason) => {
      if (retries > 0) {
        return wait(delay)
          .then(retryOperation.bind(null, operation, delay, retries - 1))
          .then(resolve)
          .catch(reject);
      }
      return reject(reason);
    });
});

假设func有时成功,有时失败,总是返回一个我们可以记录的字符串,您就是这样称呼它的:

代码语言:javascript
复制
retryOperation(func, 1000, 5)
  .then(console.log)
  .catch(console.log);

这里,我们调用retryOperation,要求它每秒钟重试一次,使用最大重试= 5。

如果您想要一些没有承诺的更简单的东西,RxJ将在这方面提供帮助:https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/retrywhen.md

票数 52
EN

Stack Overflow用户

发布于 2018-07-13 20:02:57

有很多很好的解决方案,现在通过异步/等待,这些问题可以不用付出很大的努力就可以解决。

如果您不介意使用递归方法,那么这就是我的解决方案。

代码语言:javascript
复制
function retry(fn, retries=3, err=null) {
  if (!retries) {
    return Promise.reject(err);
  }
  return fn().catch(err => {
      return retry(fn, (retries - 1), err);
    });
}
票数 39
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38213668

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档