I have seen a number of questions around retrying Promises, however what I'm looking to do is slightly different in that I'd like to manage the retrying/rejecting of promises conditionally until the max retries have been reached.
To give a simple example, imagine we wrap a promise around an XMLHttpRequest
. When the request loads with a status of...
200
: resolve the Promise299
: retry immediately399
: reject immediately499
: fetch something from server, then retry
Notice that there is scope here for asynchronous behavior to be executed before retries.
The solution I have been looking into involves two Promises.
- The first is a wrapper around each attempt and does a simple resolve/reject based on the result of that attempt.
- The second is a wrapper around the set of attempts, which handles rejections of the individual Promises conditionally.
Bringing this back to the example I mentioned...
- The first Promise manages each
XmlHttpRequest
, resolving on status200
and rejecting otherwise. - The second Promise resolves itself when any of the attempts are resolved. Whenever an attempt is rejected, it decides on the next action (retry, reject, fetch then retry etc.) based on that attempt's status code.
I think I'm going in the right direction with this, but can't seem to get a concrete solution in place. I'm looking to create a generic wrapper for this kind of 'conditionally retrying promise.'
Edit:
Here is a solution in progress:
async function tryAtMost(maxAttempts, asyncCall, handleError)
{
for (let i = 0; i < maxAttempts; i++)
{
try
{
return await asyncCall();
}
catch (error)
{
const nextAction = await handleError(error); // await some async request (if available) before proceeding
const actionError = new Error(nextAction.error);
switch (nextAction.type)
{
case ACTIONS.ABORT:
throw actionError;
case ACTIONS.RETRY:
if (i === maxAttempts - 1) { throw actionError; }
else { continue; }
}
}
}
}