I thought I could also throw a hat in the ring using ES6 Promises ...
function until_success(executor){ var before_retry = undefined; var outer_executor = function(succeed, reject){ var rejection_handler = function(err){ if(before_retry){ try { var pre_retry_result = before_retry(err); if(pre_retry_result) return succeed(pre_retry_result); } catch (pre_retry_error){ return reject(pre_retry_error); } } return new Promise(executor).then(succeed, rejection_handler); } return new Promise(executor).then(succeed, rejection_handler); } var outer_promise = new Promise(outer_executor); outer_promise.before_retry = function(func){ before_retry = func; return outer_promise; } return outer_promise; }
The executor argument is the same as the one passed to the Promise constructor, but will be called again until it activates the Call Back success. The before_retry function allows you to configure errors for failed attempts. If it returns true value, it will be considered a form of success, and the "cycle" will end, and this will result in truthfulness. If the before_retry function before_retry not registered or does not return false, then the loop will execute for another iteration. The third option is that the before_retry function throws an error. If this happens, the "cycle" will end, passing this error as an error.
Here is an example:
var counter = 0; function task(succ, reject){ setTimeout(function(){ if(++counter < 5) reject(counter + " is too small!!"); else succ(counter + " is just right"); }, 500); // simulated async task } until_success(task) .before_retry(function(err){ console.log("failed attempt: " + err); // Option 0: return falsey value and move on to next attempt // return // Option 1: uncomment to get early success.. //if(err === "3 is too small!!") // return "3 is sort of ok"; // Option 2: uncomment to get complete failure.. //if(err === "3 is too small!!") // throw "3rd time, very unlucky"; }).then(function(val){ console.log("finally, success: " + val); }).catch(function(err){ console.log("it didn't end well: " + err); })
Output for option 0:
failed attempt: 1 is too small!! failed attempt: 2 is too small!! failed attempt: 3 is too small!! failed attempt: 4 is too small!! finally, success: 5 is just right
Output for option 1:
failed attempt: 1 is too small!! failed attempt: 2 is too small!! failed attempt: 3 is too small!! finally, success: 3 is sort of ok
Output for option 2:
failed attempt: 1 is too small!! failed attempt: 2 is too small!! failed attempt: 3 is too small!! it didn't end well: 3rd time, very unlucky
dan-man Mar 03 '16 at 20:32 2016-03-03 20:32
source share