Я подумал, что с тем же успехом мог бы бросить свою шляпу на ринг, используя обещания ES6...
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;
}
Аргумент executor
такой же, как и переданный в конструктор Promise
, но будет вызываться неоднократно, пока не вызовет обратный вызов успеха. Функция before_retry
позволяет настраивать обработку ошибок при неудачных попытках. Если он возвращает истинное значение, это будет считаться формой успеха, и «цикл» завершится с этим правдивым результатом. Если функция before_retry
не зарегистрирована или возвращает ложное значение, цикл будет выполняться для другой итерации. Третий вариант заключается в том, что функция before_retry
сама выдает ошибку. Если это произойдет, то «цикл» завершится, передавая эту ошибку как ошибку.
Вот пример:
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);
})
Выход для варианта 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
Выход для варианта 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
Выход для варианта 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
person
dan-man
schedule
03.03.2016