| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- /**
- * 异步操作重试工具函数
- * @param {Function} asyncFn - 需要重试的异步函数
- * @param {Object} options - 重试配置选项
- * @param {number} options.maxRetries - 最大重试次数 (默认: 3)
- * @param {number} options.delay - 重试延迟时间(ms) (默认: 1000)
- * @param {string} options.backoffStrategy - 退避策略 ('fixed' | 'exponential' | 'linear') (默认: 'fixed')
- * @param {number} options.backoffFactor - 退避因子 (默认: 2)
- * @param {Function} options.shouldRetry - 自定义重试条件函数 (默认: 所有错误都重试)
- * @param {Function} options.onRetry - 重试回调函数
- * @param {number} options.timeout - 单次操作超时时间(ms)
- * @returns {Promise} 返回异步操作的结果
- */
- export async function retryAsync(asyncFn, options = {}) {
- const {
- maxRetries = 3,
- delay = 1000,
- backoffStrategy = 'fixed',
- backoffFactor = 2,
- shouldRetry = () => true,
- onRetry = () => {},
- timeout
- } = options;
- let lastError;
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
- try {
- // 如果设置了超时时间,包装函数添加超时控制
- const result = timeout ?
- await withTimeout(asyncFn, timeout) :
- await asyncFn();
- return result;
- } catch (error) {
- lastError = error;
- // 如果是最后一次尝试,直接抛出错误
- if (attempt === maxRetries) {
- throw error;
- }
- // 检查是否应该重试
- if (!shouldRetry(error, attempt + 1)) {
- throw error;
- }
- // 执行重试回调
- onRetry(error, attempt + 1, maxRetries);
- // 计算延迟时间并等待
- const waitTime = calculateDelay(delay, attempt, backoffStrategy, backoffFactor);
- await sleep(waitTime);
- }
- }
- throw lastError;
- }
- /**
- * 计算重试延迟时间
- */
- function calculateDelay(baseDelay, attempt, strategy, factor) {
- switch (strategy) {
- case 'exponential':
- return baseDelay * Math.pow(factor, attempt);
- case 'linear':
- return baseDelay * (attempt + 1);
- case 'fixed':
- default:
- return baseDelay;
- }
- }
- /**
- * 延迟函数
- */
- function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
- }
- /**
- * 为异步函数添加超时控制
- */
- function withTimeout(asyncFn, timeoutMs) {
- return new Promise((resolve, reject) => {
- let isResolved = false;
- const timer = setTimeout(() => {
- if (!isResolved) {
- isResolved = true;
- reject(new Error(`Operation timed out after ${timeoutMs}ms`));
- }
- }, timeoutMs);
- asyncFn()
- .then(result => {
- if (!isResolved) {
- isResolved = true;
- clearTimeout(timer);
- resolve(result);
- }
- })
- .catch(error => {
- if (!isResolved) {
- isResolved = true;
- clearTimeout(timer);
- reject(error);
- }
- });
- });
- }
|