Reputation: 767
I try to give out a general solution for retrying a promise. Below is my way and comes an error of "Uncaught (in promise)".
How can I fix this problem?
function tryAtMost(maxRetries, promise) {
let tries = maxRetries
return new Promise(function(resolve, reject) {
promise.then((result) => {
resolve(result)
})
.catch(err => {
if (tries > 0) {
console.log(`tries with ${tries}`)
tryAtMost(--tries, promise);
} else {
reject(err)
}
})
})
}
tryAtMost(3, promise).then(result => {
console.log(result)
})
.catch(err => {
console.log(err)
})
Upvotes: 2
Views: 2828
Reputation: 1074335
The reason for what you asked about is that you're missing a call to resolve
in your catch
:
.catch(err => {
if (tries > 0) {
console.log(`tries with ${tries}`);
resolve(tryAtMost(--tries, promise)); // <=== ****
}
else {
reject(err)
}
})
...and so you're creating a promise that is never handled by anything, and so if it rejects, you'll get an unhandled rejection.
But, tryAtMost
has a problem: It cannot work with the information you've given it, because it doesn't know what to try. You need to pass it an executor, not a promise, because it's the work of the executor that you need to retry. This also makes the function a lot simpler:
function tryAtMost(tries, executor) {
--tries;
return new Promise(executor)
.catch(err => tries > 0 ? tryAtMost(tries, executor) : Promise.reject(err));
}
Use:
tryAtMost(4, (resolve, reject) => {
// The thing to (re)try
});
Example:
function tryAtMost(tries, executor) {
console.log(`trying, tries = ${tries}`);
--tries;
return new Promise(executor)
.catch(err => tries > 0 ? tryAtMost(tries, executor) : Promise.reject(err));
}
tryAtMost(4, (resolve, reject) => {
const val = Math.random();
if (val < 0.3) {
resolve(val);
} else {
reject(val);
}
})
.then(result => console.log(result))
.catch(err => console.error(err));
Upvotes: 5