实现重试函数

本文最后更新于:2023年3月19日 晚上

实现重试函数,Promiseify

实现一个方法 useRetryable,当调用 retryableFn 时,它的调用方式要与原始函数(即 fn)保持一致。
同时还具备重试功能:

  1. 如果 n 次内执行失败,进行重试;
  2. 一旦执行成功,就不再执行多余的次数了;
  3. 如果 n 次全部失败,抛出最后一次的异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
//实现一个方法
function useRetryable(fn, time) {}

const retryableFn = useRetryable(fn, 3);

/**
*当调用retryableFn时,它的调用方式要与原始函数(即fn)保持一致。同时还具备重试功能:
*1、如果n次内执行失败,进行重试;
*2、一旦执行成功,就不再执行多余的次数了;
*3、如果n次全部失败,抛出最后一次的异常。
*/

retryableFn();

思路

使用 Promiseify 的思想,返回一个 Promise,同时处理同步和异步方法:

  1. 使用 try-catch 捕捉同步方法的错误。
  2. 使用 res 存储执行方法的 return 值,判断是否属于 Promise。
    1. 是异步的方法,无法使用 try-catch 捕捉,使用 Promise 的 catch 进行错误处理
  3. 两个错误处理中,判断当 time 是否大于 1,是的话继续返回 useRetryable 并立即执行,不是的话抛出错误。

解答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//实现一个方法
function useRetryable(fn, time) {
return (...args) =>
new Promise(async (resolve, reject) => {
try {
const res = fn.apply(globalThis, args);
if (res instanceof Promise) {
res.catch((err) => {
if (time > 1) useRetryable(fn, --time)(...args);
else throw Error(err);
});
}
} catch (err) {
if (time > 1) useRetryable(fn, --time)(...args);
else throw Error(err);
}
});
}

const asyncfn = async (...args) => {
const num = Math.round(Math.random() * 10);
console.log(num);
// 模拟错误,小于3才成功
return new Promise((resolve, reject) => {
if (num < 3) {
console.log(args);
resolve(num);
} else {
reject("error");
}
});
};

const syncfn = (...args) => {
const num = Math.round(Math.random() * 10);
// 模拟错误,小于3才成功
console.log(num);
if (num < 3) {
console.log(args);
} else throw new Error("error");
};

const retryableFnAsync = useRetryable(asyncfn, 3);
const retryableFnSync = useRetryable(syncfn, 3);
/**
*当调用retryableFn时,它的调用方式要与原始函数(即fn)保持一致。同时还具备重试功能:
*1、如果n次内执行失败,进行重试;
*2、一旦执行成功,就不再执行多余的次数了;
*3、如果n次全部失败,抛出最后一次的异常。
*/
retryableFnAsync(222, 333, 444);
retryableFnSync(222, 333, 444);