delay
and
maxRetries
).delay
and
maxRetries
).delay
provided).Code for #1. Keeps on retrying until promise resolves (any improvements community for the language etc?)
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();
});
};
Use
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 keep on retrying until a condition meets on the then
result in a reusable way (condition is what will vary).
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);
Something a bit different ...
Async retries can be achieved by building a .catch()
chain, as opposed to the more usual .then()
chain.
This approach is :
Otherwise, use a recursive solution.
First, a utility function to be used as a .catch()
callback.
var t = 500;
function rejectDelay(reason) {
return new Promise(function(resolve, reject) {
setTimeout(reject.bind(null, reason), t);
});
}
Now you can build .catch chains very concisely :
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
Having got your mind round (1) and (2), a combined test+delay is equally trivial.
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()
can be synchronous or asynchronous.
It would also be trivial to add further tests. Simply sandwich a chain of thens between the two catches.
p = p.catch(attempt).then(test1).then(test2).then(test3).catch(rejectDelay);
DEMO: https://jsfiddle.net/duL0qjqe/3/
All versions are designed for attempt
to be a promise-returning async function. It could also conceivably return a value, in which case the chain would follow its success path to the next/terminal .then()
.