javascript - 如何重试 Promise 解决 N 次,尝试之间有延迟?
问题描述
我想要一些 JavaScript 代码将 3 个东西作为参数:
- 返回 Promise 的函数。
- 最大尝试次数。
- 每次尝试之间的延迟。
我最终做的是使用for
循环。我不想使用递归函数:这样,即使有 50 次尝试,调用堆栈也不会长 50 行。
这是代码的打字稿版本:
/**
* @async
* @function tryNTimes<T> Tries to resolve a {@link Promise<T>} N times, with a delay between each attempt.
* @param {Object} options Options for the attempts.
* @param {() => Promise<T>} options.toTry The {@link Promise<T>} to try to resolve.
* @param {number} [options.times=5] The maximum number of attempts (must be greater than 0).
* @param {number} [options.interval=1] The interval of time between each attempt in seconds.
* @returns {Promise<T>} The resolution of the {@link Promise<T>}.
*/
export async function tryNTimes<T>(
{
toTry,
times = 5,
interval = 1,
}:
{
toTry: () => Promise<T>,
times?: number,
interval?: number,
}
): Promise<T> {
if (times < 1) throw new Error(`Bad argument: 'times' must be greater than 0, but ${times} was received.`);
let attemptCount: number;
for (attemptCount = 1; attemptCount <= times; attemptCount++) {
let error: boolean = false;
const result = await toTry().catch((reason) => {
error = true;
return reason;
});
if (error) {
if (attemptCount < times) await delay(interval);
else return Promise.reject(result);
}
else return result;
}
}
上面使用的delay
函数是一个承诺超时:
/**
* @function delay Delays the execution of an action.
* @param {number} time The time to wait in seconds.
* @returns {Promise<void>}
*/
export function delay(time: number): Promise<void> {
return new Promise<void>((resolve) => setTimeout(resolve, time * 1000));
}
澄清一下:上面的代码有效,我只是想知道这是否是一种“好”的方式,如果不是,我该如何改进它。
有什么建议吗?在此先感谢您的帮助。
解决方案
我不想使用递归函数:这样,即使有 50 次尝试,调用堆栈也不会长 50 行。
这不是一个好的借口。调用堆栈不会从异步调用中溢出,当递归解决方案比迭代解决方案更直观时,您可能应该选择它。
我最终做的是使用
for
循环。这是一种“好”的方式吗?如果不是,我该如何改进它?
for
循环很好。虽然它开始有点奇怪,1
但基于 0 的循环更加惯用。
然而,不好的是你奇怪的错误处理。该布尔error
标志不应在您的代码中占有一席之地。使用.catch()
很好,但try
/catch
也可以正常工作,应该是首选。
export async function tryNTimes<T>({ toTry, times = 5, interval = 1}) {
if (times < 1) throw new Error(`Bad argument: 'times' must be greater than 0, but ${times} was received.`);
let attemptCount = 0
while (true) {
try {
const result = await toTry();
return result;
} catch(error) {
if (++attemptCount >= times) throw error;
}
await delay(interval)
}
}
推荐阅读
- javascript - 在新的 AngularFire 7 (Firebase 9) 中实现云函数时出现未知语法错误
- ansible - 如果已创建 VM,Ansible vmware_guest customize_spec 不会更改任何内容
- python - 如何使具有多个答案的问题/答案成为可能
- python-3.x - Spacy 在 Pardo 中中断序列化 - Apache Beam
- powershell - 提示时如何将参数作为输入传递给powershell脚本?
- sqlite - 如何强制 nHibernate 自动更新引用对象?
- jupyter-notebook - 用于情节热图的交互式 zmax?
- javascript - 如何存储多个复选框的变量以供以后在同一网页上使用?
- javascript - 不同类型的位置固定但结果相同
- javascript - 我可以通过 javascript 获取背景图像源的大小吗?