Skip to content

guard

保护异步函数,捕获错误并返回统一的结果格式。

基础用法

typescript
import { guard } from 'radash'

const result = await guard(async () => {
  const response = await fetch('https://api.example.com/data')
  return response.json()
})

if (result.error) {
  console.log('Error:', result.error)
} else {
  console.log('Data:', result.data)
}

语法

typescript
function guard<T>(
  fn: () => Promise<T>
): Promise<{ data: T | null; error: Error | null }>

参数

  • fn (function): 要保护的异步函数

返回值

返回一个Promise,解析为包含data和error的对象。

示例

基本错误处理

typescript
import { guard } from 'radash'

async function fetchUserData(userId: number) {
  const result = await guard(async () => {
    const response = await fetch(`/api/users/${userId}`)
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`)
    }
    return response.json()
  })

  if (result.error) {
    console.error('Failed to fetch user:', result.error.message)
    return null
  }

  return result.data
}

const user = await fetchUserData(123)

处理网络请求

typescript
import { guard } from 'radash'

async function makeApiCall(url: string) {
  const result = await guard(async () => {
    const response = await fetch(url)
    if (!response.ok) {
      throw new Error(`Request failed: ${response.status}`)
    }
    return response.json()
  })

  return result
}

const apiResult = await makeApiCall('https://api.example.com/data')
if (apiResult.error) {
  console.log('API Error:', apiResult.error.message)
} else {
  console.log('API Data:', apiResult.data)
}

处理数据库操作

typescript
import { guard } from 'radash'

async function createUser(userData: any) {
  const result = await guard(async () => {
    // 模拟数据库操作
    if (userData.email.includes('test')) {
      throw new Error('Test emails are not allowed')
    }
    
    return {
      id: Date.now(),
      ...userData,
      createdAt: new Date()
    }
  })

  if (result.error) {
    console.error('User creation failed:', result.error.message)
    return null
  }

  return result.data
}

const newUser = await createUser({
  name: 'John Doe',
  email: 'john@example.com'
})

处理文件操作

typescript
import { guard } from 'radash'

async function readFileContent(filePath: string) {
  const result = await guard(async () => {
    const fs = await import('fs/promises')
    const content = await fs.readFile(filePath, 'utf-8')
    return JSON.parse(content)
  })

  if (result.error) {
    console.error('File read error:', result.error.message)
    return null
  }

  return result.data
}

const config = await readFileContent('./config.json')
if (config) {
  console.log('Config loaded:', config)
}

处理多个异步操作

typescript
import { guard } from 'radash'

async function processMultipleTasks() {
  const tasks = [
    guard(async () => {
      await new Promise(resolve => setTimeout(resolve, 100))
      return 'Task 1 completed'
    }),
    guard(async () => {
      await new Promise(resolve => setTimeout(resolve, 200))
      throw new Error('Task 2 failed')
    }),
    guard(async () => {
      await new Promise(resolve => setTimeout(resolve, 150))
      return 'Task 3 completed'
    })
  ]

  const results = await Promise.all(tasks)
  
  results.forEach((result, index) => {
    if (result.error) {
      console.log(`Task ${index + 1} failed:`, result.error.message)
    } else {
      console.log(`Task ${index + 1} succeeded:`, result.data)
    }
  })
}

await processMultipleTasks()

处理超时操作

typescript
import { guard } from 'radash'

async function fetchWithTimeout(url: string, timeout: number) {
  const result = await guard(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
    }
  })

  return result
}

const data = await fetchWithTimeout('https://api.example.com/data', 5000)
if (data.error) {
  console.log('Request failed:', data.error.message)
} else {
  console.log('Data received:', data.data)
}

处理重试逻辑

typescript
import { guard } from 'radash'

async function fetchWithRetry(url: string, maxRetries: number = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const result = await guard(async () => {
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`)
      }
      return response.json()
    })

    if (!result.error) {
      return result.data
    }

    console.log(`Attempt ${attempt} failed:`, result.error.message)
    
    if (attempt < maxRetries) {
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
    }
  }

  throw new Error(`Failed after ${maxRetries} attempts`)
}

try {
  const data = await fetchWithRetry('https://api.example.com/data')
  console.log('Success:', data)
} catch (error) {
  console.error('All attempts failed:', error.message)
}

处理并发操作

typescript
import { guard } from 'radash'

async function processConcurrentRequests(urls: string[]) {
  const requests = urls.map(url =>
    guard(async () => {
      const response = await fetch(url)
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`)
      }
      return response.json()
    })
  )

  const results = await Promise.all(requests)
  
  const successful = results.filter(r => !r.error)
  const failed = results.filter(r => r.error)
  
  console.log(`Successful: ${successful.length}, Failed: ${failed.length}`)
  
  return {
    successful: successful.map(r => r.data),
    failed: failed.map(r => r.error)
  }
}

const urls = [
  'https://api.example.com/users',
  'https://api.example.com/posts',
  'https://api.example.com/comments'
]

const { successful, failed } = await processConcurrentRequests(urls)

处理条件操作

typescript
import { guard } from 'radash'

async function conditionalOperation(shouldFail: boolean) {
  const result = await guard(async () => {
    if (shouldFail) {
      throw new Error('Operation failed as requested')
    }
    
    // 模拟成功操作
    await new Promise(resolve => setTimeout(resolve, 100))
    return { success: true, timestamp: Date.now() }
  })

  return result
}

// 成功的情况
const successResult = await conditionalOperation(false)
if (successResult.data) {
  console.log('Operation succeeded:', successResult.data)
}

// 失败的情况
const failureResult = await conditionalOperation(true)
if (failureResult.error) {
  console.log('Operation failed:', failureResult.error.message)
}

处理复杂错误处理

typescript
import { guard } from 'radash'

class CustomError extends Error {
  constructor(message: string, public code: string) {
    super(message)
    this.name = 'CustomError'
  }
}

async function complexOperation() {
  const result = await guard(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' }
  })

  if (result.error) {
    if (result.error instanceof CustomError) {
      switch (result.error.code) {
        case 'NETWORK_ERROR':
          console.log('Network issue, retrying...')
          break
        case 'VALIDATION_ERROR':
          console.log('Invalid input data')
          break
        case 'SERVER_ERROR':
          console.log('Server is down')
          break
      }
    } else {
      console.log('Unknown error:', result.error.message)
    }
    return null
  }

  return result.data
}

const result = await complexOperation()

注意事项

  1. 错误捕获: 捕获所有类型的错误,包括同步和异步错误
  2. 统一格式: 返回统一的结果格式,便于处理
  3. 类型安全: 提供完整的TypeScript类型支持
  4. 性能: 对性能影响很小,只是简单的错误包装
  5. 链式调用: 可以与其他异步函数链式调用

与其他方法的区别

  • try/catch: 需要手动处理错误,guard 提供统一格式
  • Promise.catch(): 只处理Promise错误,guard 处理所有错误
  • guard(): radash提供的简洁的错误处理工具

实际应用场景

  1. API调用: 处理网络请求错误
  2. 数据库操作: 处理数据库连接和查询错误
  3. 文件操作: 处理文件读写错误
  4. 第三方服务: 处理外部服务调用错误
  5. 业务逻辑: 保护复杂的业务操作

Released under the MIT License.