When programming in JavaScript, Promises are an elegant way of handling values that will be available after some asynchronous operation completes. One trick I particularly like is making Promises for a user-retriable operation that will eventually resolve with the proper value, no matter which try is the one that succeeds.
For a function that handles the retry UI itself and returns such a Promise:
[code language=”javascript”]
function magic() {
// You’d do asynchronous work, declaring "promise" with a Promise
// and "nextAttempt" with a Promise-returning function, and then…
return promise.catch( function catcher(error) {
var waitOnUser = new Promise( function(resolve) {
// Show UI to the end user; call resolve when they request a retry
} );
return waitOnUser.then(nextAttempt).catch(catcher);
} );
}
[/code]
If you’d prefer to leave the retry UI to the function’s consumer (only recommended if only a single consumer directly handles the return value):
[code language=”javascript”]
function magic() {
// Declare "promise" and "nextAttempt" as above, then…
return promise.catch( function catcher(error) {
var endWait;
var waitOnUser = new Promise( function(resolve) {
endWait = resolve;
} );
return {
error: error,
retry: endWait,
retryResult: waitonUser.then(nextAttempt)
};
} );
}
// The consumer’s rejection handler, if named "handler" with a parameter "obj",
// would return obj.retryResult.catch(handler)
[/code]
Deviant Love uses a variant of the second version above – rather than return a promise directly, researchLove returns an object with multiple Promises and various methods to act on operations in progress, and retry
is a method of said object rather than included with a rejection value.
Naturally, this pattern is useful only if magic
can use partially-completed work across attempts. If it would have to throw out everything and start over for a new attempt, the KISS principle dictates you should just call magic
again when the user requests a retry.