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調用: 處理網絡不穩定的情況
- 數據庫操作: 處理連接失敗
- 文件操作: 處理文件鎖定
- 第三方服務: 處理服務不可用
- 網絡請求: 處理超時和連接錯誤