chore: initialize qiming workspace repository
This commit is contained in:
112
qiming-mobile/uni_modules/x-tools/tools/retryAsync.js
Normal file
112
qiming-mobile/uni_modules/x-tools/tools/retryAsync.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* 异步操作重试工具函数
|
||||
* @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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user