使用 promises 时如何在 Javascript 出现异常后重试?
How can you retry after an exception in Javascript when using promises?
我正在使用 Bluebird promise 库。我有一连串的 promisified 函数如下:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.spread(function(response, data) {
return sendResponseAsync(response);
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// handle error here
});
有时 sendMessage 会失败,比方说,要响应的服务器不可用。我希望代码继续尝试永远响应,直到成功为止。你不能简单地将 sendMessage 包装在一个 catch 中,因为它实际上并没有抛出异常,我想,它调用了 "error" 函数,在这个 promisified 代码中,它是底部的 "catch" 。所以必须有一些方法可以 "retry" 在 "catch" 部分发送消息。问题是,即使我在 "catch" 中循环重试,我仍然无法跳转到承诺链并执行剩余的承诺功能。我该如何处理?
编辑:
我对 HTTP post 的重试结果如下所示:
function retry(func) {
return func()
.spread(function(httpResponse) {
if (httpResponse.statusCode != 200) {
Log.error("HTTP post returned error status: "+httpResponse.statusCode);
Sleep.sleep(5);
return retry(func);
}
})
.catch(function(err) {
Log.err("Unable to send response via HTTP");
Sleep.sleep(5);
return retry(func);
});
}
这是一个示例重试函数(尚未测试):
function retry(maxRetries, fn) {
return fn().catch(function(err) {
if (maxRetries <= 0) {
throw err;
}
return retry(maxRetries - 1, fn);
});
}
这个想法是,您可以包装一个 returns 承诺的函数,该函数将捕获并重试错误,直到 运行 重试失败。所以如果你要重试 sendResponseAsync
:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.spread(function(response, data) {
return retry(3, function () { return sendResponseAsync(response); });
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// handle error here
});
由于 retry
承诺在所有重试都用完之前不会真正抛出,因此您的调用链可以继续。
编辑:
当然,如果你愿意,你可以永远循环:
function retryForever(fn) {
return fn().catch(function(err) {
return retryForever(fn);
});
}
这是一个小帮手,其作用类似于 then
但会重试该功能。
Promise.prototype.retry = function retry(onFulfilled, onRejected, n){
n = n || 3; // default to 3 retries
return this.then(function(result) {
return Promise.try(function(){
return onFulfilled(result); // guard against synchronous errors too
}).catch(function(err){
if(n <= 0) throw err;
return this.retry(onFulfilled, onRejected, n - 1);
}.bind(this)); // keep `this` value
}.bind(this), onRejected);
};
哪个可以让您编写更漂亮的代码,例如:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.retry(function(response, data) {
return sendResponseAsync(response); // will retry this 3 times
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// I don't like catch alls :/ Consider using `.error` instead.
});
我刚刚发布了 https://github.com/zyklus/promise-repeat,它会重试承诺,直到超时或达到最大尝试次数。它允许你写:
receiveMessageAsync(params)
...
.spread(retry(
function(response, data) {
return sendResponseAsync(response);
}
))
...
我正在使用 Bluebird promise 库。我有一连串的 promisified 函数如下:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.spread(function(response, data) {
return sendResponseAsync(response);
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// handle error here
});
有时 sendMessage 会失败,比方说,要响应的服务器不可用。我希望代码继续尝试永远响应,直到成功为止。你不能简单地将 sendMessage 包装在一个 catch 中,因为它实际上并没有抛出异常,我想,它调用了 "error" 函数,在这个 promisified 代码中,它是底部的 "catch" 。所以必须有一些方法可以 "retry" 在 "catch" 部分发送消息。问题是,即使我在 "catch" 中循环重试,我仍然无法跳转到承诺链并执行剩余的承诺功能。我该如何处理?
编辑:
我对 HTTP post 的重试结果如下所示:
function retry(func) {
return func()
.spread(function(httpResponse) {
if (httpResponse.statusCode != 200) {
Log.error("HTTP post returned error status: "+httpResponse.statusCode);
Sleep.sleep(5);
return retry(func);
}
})
.catch(function(err) {
Log.err("Unable to send response via HTTP");
Sleep.sleep(5);
return retry(func);
});
}
这是一个示例重试函数(尚未测试):
function retry(maxRetries, fn) {
return fn().catch(function(err) {
if (maxRetries <= 0) {
throw err;
}
return retry(maxRetries - 1, fn);
});
}
这个想法是,您可以包装一个 returns 承诺的函数,该函数将捕获并重试错误,直到 运行 重试失败。所以如果你要重试 sendResponseAsync
:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.spread(function(response, data) {
return retry(3, function () { return sendResponseAsync(response); });
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// handle error here
});
由于 retry
承诺在所有重试都用完之前不会真正抛出,因此您的调用链可以继续。
编辑:
当然,如果你愿意,你可以永远循环:
function retryForever(fn) {
return fn().catch(function(err) {
return retryForever(fn);
});
}
这是一个小帮手,其作用类似于 then
但会重试该功能。
Promise.prototype.retry = function retry(onFulfilled, onRejected, n){
n = n || 3; // default to 3 retries
return this.then(function(result) {
return Promise.try(function(){
return onFulfilled(result); // guard against synchronous errors too
}).catch(function(err){
if(n <= 0) throw err;
return this.retry(onFulfilled, onRejected, n - 1);
}.bind(this)); // keep `this` value
}.bind(this), onRejected);
};
哪个可以让您编写更漂亮的代码,例如:
receiveMessageAsync(params)
.then(function(data)) {
return [data, handleMessageAsync(request)];
})
.spread(function(data, response) {
return [response, deleteMessageAsync(request)];
})
.retry(function(response, data) {
return sendResponseAsync(response); // will retry this 3 times
})
.then(function(data) {
return waitForMessage(data);
})
.catch (function(err) {
// I don't like catch alls :/ Consider using `.error` instead.
});
我刚刚发布了 https://github.com/zyklus/promise-repeat,它会重试承诺,直到超时或达到最大尝试次数。它允许你写:
receiveMessageAsync(params)
...
.spread(retry(
function(response, data) {
return sendResponseAsync(response);
}
))
...