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:
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); } ); }
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):
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)
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.