Skip to content

tryit

安全地執行異步函數,返回 [error, result] 元組。

語法

typescript
tryit<T>(
  fn: () => Promise<T>
): Promise<[Error | null, T | null]>

tryit<T, Args extends any[]>(
  fn: (...args: Args) => Promise<T>,
  ...args: Args
): Promise<[Error | null, T | null]>

參數

  • fn (() => Promise<T> | (...args: Args) => Promise<T>): 要執行的異步函數
  • ...args (Args, 可選): 傳遞給函數的參數

返回值

  • Promise<[Error | null, T | null]>: 包含錯誤和結果的元組

示例

基本用法

typescript
import { tryit } from 'radash'

const fetchUser = async (id: number) => {
  const response = await fetch(`/api/users/${id}`)
  return response.json()
}

const [err, user] = await tryit(fetchUser, 123)

if (err) {
  console.error('Failed to fetch user:', err)
} else {
  console.log('User:', user)
}

處理網絡請求

typescript
import { tryit } from 'radash'

const [err, data] = await tryit(fetch)('/api/users')

if (err) {
  console.error('Network error:', err)
  return
}

const users = await data.json()
console.log('Users:', users)

處理文件操作

typescript
import { tryit } from 'radash'
import { readFile } from 'fs/promises'

const [err, content] = await tryit(readFile)('config.json', 'utf8')

if (err) {
  console.error('Failed to read file:', err)
  // 使用默認配置
  return defaultConfig
}

const config = JSON.parse(content)
console.log('Config loaded:', config)

處理數據庫操作

typescript
import { tryit } from 'radash'

const createUser = async (userData: any) => {
  return await db.query(
    'INSERT INTO users (name, email) VALUES (?, ?)',
    [userData.name, userData.email]
  )
}

const [err, result] = await tryit(createUser, {
  name: 'Alice',
  email: 'alice@example.com'
})

if (err) {
  console.error('Failed to create user:', err)
  return { success: false, error: err.message }
}

return { success: true, userId: result.insertId }

處理多個操作

typescript
import { tryit } from 'radash'

const operations = [
  () => fetch('/api/users'),
  () => fetch('/api/posts'),
  () => fetch('/api/comments')
]

const results = await Promise.all(
  operations.map(op => tryit(op))
)

const errors = results.filter(([err]) => err)
const successes = results.filter(([, data]) => data)

console.log('Errors:', errors.length)
console.log('Successes:', successes.length)

處理超時

typescript
import { tryit } from 'radash'

const timeout = (ms: number) => 
  new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Timeout')), ms)
  )

const slowOperation = async () => {
  await new Promise(resolve => setTimeout(resolve, 2000))
  return 'Operation completed'
}

const [err, result] = await tryit(async () => {
  return await Promise.race([
    slowOperation(),
    timeout(1000)
  ])
})

if (err) {
  console.error('Operation timed out:', err)
} else {
  console.log('Result:', result)
}

處理驗證

typescript
import { tryit } from 'radash'

const validateUser = async (userData: any) => {
  if (!userData.email) {
    throw new Error('Email is required')
  }
  
  if (!userData.email.includes('@')) {
    throw new Error('Invalid email format')
  }
  
  return userData
}

const [err, validatedUser] = await tryit(validateUser, {
  name: 'Alice',
  email: 'invalid-email'
})

if (err) {
  console.error('Validation failed:', err.message)
  return { success: false, error: err.message }
}

console.log('User validated:', validatedUser)

處理第三方API

typescript
import { tryit } from 'radash'

const callExternalAPI = async (endpoint: string) => {
  const response = await fetch(`https://api.external.com/${endpoint}`)
  
  if (!response.ok) {
    throw new Error(`API error: ${response.status}`)
  }
  
  return response.json()
}

const [err, data] = await tryit(callExternalAPI, 'users/123')

if (err) {
  console.error('External API error:', err)
  // 使用緩存數據或默認值
  return cachedData
}

console.log('External API data:', data)

處理文件上傳

typescript
import { tryit } from 'radash'

const uploadFile = async (file: File) => {
  const formData = new FormData()
  formData.append('file', file)
  
  const response = await fetch('/api/upload', {
    method: 'POST',
    body: formData
  })
  
  if (!response.ok) {
    throw new Error(`Upload failed: ${response.status}`)
  }
  
  return response.json()
}

const [err, uploadResult] = await tryit(uploadFile, fileInput.files[0])

if (err) {
  console.error('Upload failed:', err)
  showErrorMessage('文件上傳失敗')
} else {
  console.log('Upload successful:', uploadResult)
  showSuccessMessage('文件上傳成功')
}

處理並發操作

typescript
import { tryit } from 'radash'

const fetchWithRetry = async (url: string, retries = 3) => {
  for (let i = 0; i < retries; i++) {
    const [err, data] = await tryit(fetch)(url)
    
    if (!err) {
      return data
    }
    
    if (i < retries - 1) {
      await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
    }
  }
  
  throw new Error(`Failed after ${retries} retries`)
}

const [err, data] = await tryit(fetchWithRetry)('/api/unreliable-endpoint')

if (err) {
  console.error('All retries failed:', err)
} else {
  console.log('Data received:', data)
}

注意事項

  1. 錯誤處理: 總是檢查第一個元素是否為錯誤
  2. 類型安全: 支持完整的 TypeScript 類型推斷
  3. 性能: 比 try-catch 更簡潔,但功能相同
  4. 可讀性: 使錯誤處理更加明確和一致

與其他函數的區別

  • tryit: 返回 [error, result] 元組
  • try-catch: 原生錯誤處理
  • guard: 類似功能,但可能有不同的實現

性能

  • 時間復雜度: O(1)
  • 內存使用: 與原生 try-catch 相同
  • 適用場景: 需要統一錯誤處理的異步操作

Released under the MIT License.