SOURCE

/**
* 把任意一个函数,修饰生成一个带重试功能的新函数。
* 1、如果执行失败,进行重试;
* 2、如果执行成功,直接返回结果;
* 3、如果重试了 n 次依然失败,抛出最后一次的异常。
* 4、新函数的表现行为要尽可能与原函数保持一致
*
* @param {Function} fn
* @param {number} n 最大重试次数
* @return {Function} 带有重试功能的新函数
*/
//同步递归版:
function useRetryable(fn, times) {
    return function retryableFn(...arg) {
        try {
            return fn(...arg);
        } catch (error) {
            if (--times === 0) throw error;
            else return retryableFn(...arg);
        }
    };
}

// test code
// let count = 3;
// const testFunc = function () {
//     if (count > 0) {
//         count--;
//         throw Error('this is an error');
//     } else return 'yeah~~suukii';
// };

// const fn = useRetryable(testFunc, 4);
// console.log(fn());


//异步版本(递归):

function useRetryableAsync(fn, times) {
    return function retryableFn(...arg) {
        times--;
        return fn(...arg)
            .then(data => data)
            .catch(error => {
                if (times === 0) throw error;
                // notes: 要把递归的结果 return 呀
                else return retryableFn(...arg);
            });
    };
}

// test code
let count = 3;
const testFunc = function () {
    return new Promise((res, rej) => {
        setTimeout(() => {
            count > 0 ? rej('this is an error') : res('yeah~~suukii');
            count--;
        }, 100);
    });
};

const fn = useRetryableAsync(testFunc, 4);
fn()
    .then(data => {
        console.log(data);
    })
    .catch(err => {
        console.log(err);
    });
console 命令行工具 X clear

                    
>
console