Edit

  1. 不断try 直到promise 解决的模式(delaydelay)
  2. 不断重试直到出现问题的模式
  3. 具有无限重试次数的高效内存动态模式(提供delay次).

Code for #1.继续try ,直到promise 解决为止(该语言社区是否有任何改进?)

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();
    });
};

使用

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);

Code for #2继续重试,直到以可重复使用的方式在then结果上满足条件(条件会有所不同).

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);

推荐答案

有点不同...

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

这种方法是:

  • 只有在指定的最大try 次数下才可能.(链条的长度必须有限),
  • 仅建议使用较低的最大值.(promise 链消耗的内存大致与其长度成正比).

否则,请使用递归解决方案.

首先,一个用作.catch()回调的实用函数.

var t = 500;

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

现在你可以建造了.非常简洁地捕捉链条:

1. Retry until the promise resolves, with delay

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);

DEMO: https://jsfiddle.net/duL0qjqe/

2. Retry until result meets some condition, without delay

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);

DEMO: https://jsfiddle.net/duL0qjqe/1/

3. Retry until result meets some condition, with delay

把你的注意力放在(1)和(2)上,组合测试+延迟同样微不足道.

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()可以是同步的,也可以是异步的.

添加进一步的测试也很简单.只需在两个渔获物之间夹上一串鱼肉.

p = p.catch(attempt).then(test1).then(test2).then(test3).catch(rejectDelay);

DEMO: https://jsfiddle.net/duL0qjqe/3/


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

Node.js相关问答推荐

Windows上使用ES6+的OpenAPI规范的Express服务器不接受嵌套路由'

聚合发布/订阅消息

JsonwebToken过期后如何注销和清除cookie?

如何在Sequelize with Postgres中将m:n关联表ID从整数迁移到UUID?

验证器功能在mongoose 中不起作用

函数声明中的异步在没有等待的函数中做什么?

通过 Node js 中的 TBA 执行 netsuite REST upsert 操作出现 401 错误

如何使用Stripe测试失败的收费?

我如何在 Raku 的供应中注册不同的事件?

在对象数组中的数组中嵌套 $lookup - Mongodb

yarn 安装失败,因为 node-gyp 正在寻找过时的 node 版本标头

错误 node :错误:绑定消息提供 16 个参数,但准备语句需要 15 个

MongoDB - 查找查询以判断是否存在少量字段,结合字段上的 AND

在 Header 中使用 Authorization 方法和新的附加参数:accessToken 有什么区别?

kubernetes 上的 nextjs 无法启动

React Native:执行 com.android.build.gradle.internal.tasks.Workers$ActionFacade 时发生故障

AWS EC2 npm install 突然很慢

在 Node.js 与 Cron 作业(job)中设置间隔?

如何为 node.js 服务器分配域名?

node --experimental-modules,请求的模块不提供名为的导出