retry
重试异步操作,直到成功或达到最大重试次数。
基础用法
typescript
import { retry } from 'radash'
const result = await retry(async () => {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
}, { attempts: 3 })
console.log(result)
语法
typescript
function retry<T>(
fn: () => Promise<T>,
options?: {
attempts?: number
delay?: number
backoff?: boolean
onRetry?: (error: Error, attempt: number) => void
}
): Promise<T>
参数
fn
(function): 要重试的异步函数options
(object, 可选): 重试选项attempts
(number, 可选): 最大重试次数,默认为3delay
(number, 可选): 重试间隔(毫秒),默认为1000backoff
(boolean, 可选): 是否使用指数退避,默认为falseonRetry
(function, 可选): 重试时的回调函数
返回值
返回一个Promise,解析为函数的最终结果。
示例
基本重试
typescript
import { retry } from 'radash'
const result = await retry(async () => {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
}, { attempts: 3 })
console.log(result)
自定义重试次数和延迟
typescript
import { retry } from 'radash'
const result = await retry(async () => {
const response = await fetch('https://api.example.com/unreliable')
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`)
}
return response.json()
}, {
attempts: 5,
delay: 2000 // 2秒延迟
})
console.log('Success:', result)
使用指数退避
typescript
import { retry } from 'radash'
const result = await retry(async () => {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
}, {
attempts: 3,
delay: 1000,
backoff: true // 使用指数退避:1s, 2s, 4s
})
console.log(result)
添加重试回调
typescript
import { retry } from 'radash'
const result = await retry(async () => {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
}, {
attempts: 3,
onRetry: (error, attempt) => {
console.log(`Attempt ${attempt} failed:`, error.message)
console.log(`Retrying in ${1000 * attempt}ms...`)
}
})
console.log('Final result:', result)
处理数据库操作
typescript
import { retry } from 'radash'
async function createUser(userData: any) {
return retry(async () => {
// 模拟数据库操作
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData)
})
if (!response.ok) {
throw new Error(`Failed to create user: ${response.status}`)
}
return response.json()
}, {
attempts: 3,
delay: 1000,
backoff: true
})
}
const newUser = await createUser({
name: 'John Doe',
email: 'john@example.com'
})
console.log('User created:', newUser)
处理文件操作
typescript
import { retry } from 'radash'
async function readFileWithRetry(filePath: string) {
return retry(async () => {
const fs = await import('fs/promises')
const content = await fs.readFile(filePath, 'utf-8')
return JSON.parse(content)
}, {
attempts: 5,
delay: 500,
onRetry: (error, attempt) => {
console.log(`File read attempt ${attempt} failed:`, error.message)
}
})
}
const config = await readFileWithRetry('./config.json')
console.log('Config loaded:', config)
处理条件重试
typescript
import { retry } from 'radash'
async function processWithConditionalRetry(shouldFail: boolean) {
return retry(async () => {
if (shouldFail) {
throw new Error('Operation failed as requested')
}
// 模拟成功操作
await new Promise(resolve => setTimeout(resolve, 100))
return { success: true, timestamp: Date.now() }
}, {
attempts: 3,
delay: 1000,
onRetry: (error, attempt) => {
console.log(`Attempt ${attempt} failed:`, error.message)
}
})
}
// 成功的情况
const successResult = await processWithConditionalRetry(false)
console.log('Success:', successResult)
// 失败的情况(会重试3次后失败)
try {
const failureResult = await processWithConditionalRetry(true)
console.log('This should not be reached')
} catch (error) {
console.log('All attempts failed:', error.message)
}
处理网络请求重试
typescript
import { retry } from 'radash'
async function fetchWithRetry(url: string) {
return retry(async () => {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000) // 10秒超时
try {
const response = await fetch(url, {
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
return response.json()
} catch (error) {
clearTimeout(timeoutId)
throw error
}
}, {
attempts: 3,
delay: 2000,
backoff: true,
onRetry: (error, attempt) => {
console.log(`Request attempt ${attempt} failed:`, error.message)
}
})
}
const data = await fetchWithRetry('https://api.example.com/data')
console.log('Data received:', data)
处理复杂错误处理
typescript
import { retry } from 'radash'
class CustomError extends Error {
constructor(message: string, public code: string) {
super(message)
this.name = 'CustomError'
}
}
async function complexOperation() {
return retry(async () => {
const random = Math.random()
if (random < 0.3) {
throw new CustomError('Network error', 'NETWORK_ERROR')
} else if (random < 0.6) {
throw new CustomError('Validation error', 'VALIDATION_ERROR')
} else if (random < 0.8) {
throw new CustomError('Server error', 'SERVER_ERROR')
}
return { message: 'Operation completed successfully' }
}, {
attempts: 5,
delay: 1000,
backoff: true,
onRetry: (error, attempt) => {
if (error instanceof CustomError) {
switch (error.code) {
case 'NETWORK_ERROR':
console.log(`Network issue on attempt ${attempt}, retrying...`)
break
case 'VALIDATION_ERROR':
console.log(`Validation error on attempt ${attempt}, retrying...`)
break
case 'SERVER_ERROR':
console.log(`Server error on attempt ${attempt}, retrying...`)
break
}
} else {
console.log(`Unknown error on attempt ${attempt}:`, error.message)
}
}
})
}
const result = await complexOperation()
console.log('Final result:', result)
处理批量操作重试
typescript
import { retry } from 'radash'
async function processBatchWithRetry(items: any[]) {
return retry(async () => {
const response = await fetch('/api/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ items })
})
if (!response.ok) {
throw new Error(`Batch processing failed: ${response.status}`)
}
return response.json()
}, {
attempts: 3,
delay: 2000,
backoff: true,
onRetry: (error, attempt) => {
console.log(`Batch processing attempt ${attempt} failed:`, error.message)
}
})
}
const items = [
{ id: 1, data: 'item1' },
{ id: 2, data: 'item2' },
{ id: 3, data: 'item3' }
]
const results = await processBatchWithRetry(items)
console.log('Batch processed:', results)
处理超时重试
typescript
import { retry } from 'radash'
async function fetchWithTimeoutAndRetry(url: string, timeout: number) {
return retry(async () => {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeout)
try {
const response = await fetch(url, {
signal: controller.signal
})
clearTimeout(timeoutId)
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
} catch (error) {
clearTimeout(timeoutId)
throw error
}
}, {
attempts: 3,
delay: 1000,
backoff: true,
onRetry: (error, attempt) => {
console.log(`Timeout attempt ${attempt} failed:`, error.message)
}
})
}
const data = await fetchWithTimeoutAndRetry('https://api.example.com/slow', 5000)
console.log('Data received:', data)
处理条件重试策略
typescript
import { retry } from 'radash'
async function smartRetry<T>(
fn: () => Promise<T>,
shouldRetry: (error: Error) => boolean
): Promise<T> {
return retry(fn, {
attempts: 3,
delay: 1000,
backoff: true,
onRetry: (error, attempt) => {
if (!shouldRetry(error)) {
console.log('Error is not retryable:', error.message)
throw error // 立即停止重试
}
console.log(`Retrying attempt ${attempt}:`, error.message)
}
})
}
// 只重试网络错误,不重试验证错误
const result = await smartRetry(
async () => {
const response = await fetch('https://api.example.com/data')
if (!response.ok) {
if (response.status === 400) {
throw new Error('Validation error')
} else {
throw new Error('Network error')
}
}
return response.json()
},
(error) => error.message === 'Network error'
)
console.log('Result:', result)
注意事项
- 错误处理: 只有抛出错误的操作才会重试
- 延迟策略: 可以使用固定延迟或指数退避
- 回调函数: 可以监听重试事件进行日志记录
- 性能: 重试会增加总执行时间
- 幂等性: 确保重试的操作是幂等的
与其他方法的区别
Promise.catch()
: 只处理错误,不重试retry()
: radash提供的专门的重试工具- 手动重试: 需要编写更多代码
实际应用场景
- API调用: 处理网络不稳定的情况
- 数据库操作: 处理连接失败
- 文件操作: 处理文件锁定
- 第三方服务: 处理服务不可用
- 网络请求: 处理超时和连接错误