我想重复执行一个操作,每次操作之间的超时时间增加,直到成功或经过一定时间。我如何用 Q 中的Promise来构建它?
Promise:重复操作直到成功?
IT技术
javascript
promise
q
2021-03-02 04:22:17
6个回答
在我看来,这里的所有答案都非常复杂。Kos 有正确的想法,但您可以通过编写更惯用的 promise 代码来缩短代码:
function retry(operation, delay) {
return operation().catch(function(reason) {
return Q.delay(delay).then(retry.bind(null, operation, delay * 2));
});
}
并附有评论:
function retry(operation, delay) {
return operation(). // run the operation
catch(function(reason) { // if it fails
return Q.delay(delay). // delay
// retry with more time
then(retry.bind(null, operation, delay * 2));
});
}
如果您想在一段时间后超时(假设 10 秒,您可以简单地执行以下操作:
var promise = retry(operation, 1000).timeout(10000);
该功能内置于 Q 中,无需重新发明它:)
这是我如何使用一些辅助函数来解决这个问题的示例。请注意,“maxTimeout”是更复杂的部分,因为您必须在两个状态之间进行比赛。
// Helper delay function to wait a specific amount of time.
function delay(time){
return new Promise(function(resolve){
setTimeout(resolve, time);
});
}
// A function to just keep retrying forever.
function runFunctionWithRetries(func, initialTimeout, increment){
return func().catch(function(err){
return delay(initialTimeout).then(function(){
return runFunctionWithRetries(
func, initialTimeout + increment, increment);
});
});
}
// Helper to retry a function, with incrementing and a max timeout.
function runFunctionWithRetriesAndMaxTimeout(
func, initialTimeout, increment, maxTimeout){
var overallTimeout = delay(maxTimeout).then(function(){
// Reset the function so that it will succeed and no
// longer keep retrying.
func = function(){ return Promise.resolve() };
throw new Error('Function hit the maximum timeout');
});
// Keep trying to execute 'func' forever.
var operation = runFunctionWithRetries(function(){
return func();
}, initialTimeout, increment);
// Wait for either the retries to succeed, or the timeout to be hit.
return Promise.race([operation, overallTimeout]);
}
然后要使用这些助手,你会做这样的事情:
// Your function that creates a promise for your task.
function doSomething(){
return new Promise(...);
}
runFunctionWithRetriesAndMaxTimeout(function(){
return doSomething();
}, 1000 /* start at 1s per try */, 500 /* inc by .5s */, 30000 /* max 30s */);
我认为你不能在Promise级别上做到这一点 - Promise不是一个操作,而只是一个将来会到达的值,所以你不能定义一个类型化的函数Promise -> Promise
来实现它。
您需要向下一层并定义一个 typed 函数Operation -> Promise
,其中 Operation 本身是 typed () -> Promise
。我假设该操作不采用任何参数 - 您可以事先部分应用它们。
这是一种递归方法,可以将每次运行的超时时间加倍:
function RepeatUntilSuccess(operation, timeout) {
var deferred = Q.defer();
operation().then(function success(value) {
deferred.resolve(value);
}, function error(reason) {
Q.delay(timeout
.then(function() {
return RepeatUntilSuccess(operation, timeout*2);
}).done(function(value) {
deferred.resolve(value);
});
});
return deferred.promise;
}
- 为“所有进程超时”分配一个布尔变量。
- 在“所有进程超时”之后调用窗口的 setTimeout 使该变量为“false”。
- 使用超时调用 promise 操作。
- 如果成功就没有问题。
- 如果失败:在 promise 的错误处理程序中,如果布尔变量为真,则再次调用 promise 函数并增加超时时间。
像这样的东西:
var goOn= true;
setTimeout(function () {
goOn= false;
}, 30000); // 30 seconds -- all process timeout
var timeout = 1000; // 1 second
(function () {
var helperFunction = function () {
callAsyncFunc().then(function () {
// success...
}, function () {
// fail
if (goOn) {
timeout += 1000; // increase timeout 1 second
helperFunction();
}
}).timeout(timeout);
}
})();
我用 Promises/A+ 做了以下事情(用 Q 应该没问题)
function delayAsync(timeMs)
{
return new Promise(function(resolve){
setTimeout(resolve, timeMs);
});
}
//use an IIFE so we can have a private scope
//to capture some state
(function(){
var a;
var interval = 1000;
a = function(){
return doSomethingAsync()
.then(function(success){
if(success)
{
return true;
}
return delayAsync(interval)
.then(function(){
interval *= 2;
})
.then(a());
});
};
a();
})();
我相信你可以弄清楚如何在最大超时后保释。
其它你可能感兴趣的问题