map
對數組中的每個元素執行異步操作,返回包含所有結果的數組。
基礎用法
typescript
import { map } from 'radash'
const numbers = [1, 2, 3, 4, 5]
const results = await map(numbers, async (num) => {
await new Promise(resolve => setTimeout(resolve, 100))
return num * 2
})
console.log(results) // [2, 4, 6, 8, 10]
語法
typescript
function map<T, U>(
array: readonly T[],
fn: (item: T, index: number, array: readonly T[]) => Promise<U>
): Promise<U[]>
參數
array
(readonly T[]): 要處理的數組fn
(function): 異步映射函數item
(T): 當前元素index
(number): 當前元素的索引array
(readonly T[]): 原數組
返回值
返回一個Promise,解析為映射後的數組。
示例
基本異步映射
typescript
import { map } from 'radash'
const urls = [
'https://api.example.com/users/1',
'https://api.example.com/users/2',
'https://api.example.com/users/3'
]
const users = await map(urls, async (url) => {
const response = await fetch(url)
return response.json()
})
console.log(users) // [user1, user2, user3]
處理對象數組
typescript
import { map } from 'radash'
const products = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Phone', price: 599 },
{ id: 3, name: 'Tablet', price: 399 }
]
const enrichedProducts = await map(products, async (product) => {
// 模擬獲取產品詳情
const details = await fetch(`/api/products/${product.id}/details`)
const productDetails = await details.json()
return {
...product,
...productDetails,
totalPrice: product.price + (productDetails.tax || 0)
}
})
console.log(enrichedProducts)
處理並發限制
typescript
import { map } from 'radash'
async function processWithConcurrency<T, U>(
items: T[],
fn: (item: T) => Promise<U>,
concurrency: number = 3
): Promise<U[]> {
const results: U[] = []
for (let i = 0; i < items.length; i += concurrency) {
const batch = items.slice(i, i + concurrency)
const batchResults = await map(batch, fn)
results.push(...batchResults)
}
return results
}
const urls = Array.from({ length: 10 }, (_, i) => `https://api.example.com/data/${i}`)
const results = await processWithConcurrency(urls, async (url) => {
const response = await fetch(url)
return response.json()
}, 3) // 最多3個並發請求
處理錯誤情況
typescript
import { map } from 'radash'
const numbers = [1, 2, 3, 4, 5]
const results = await map(numbers, async (num) => {
if (num === 3) {
throw new Error('Number 3 is not allowed')
}
await new Promise(resolve => setTimeout(resolve, 100))
return num * 2
})
// 如果任何操作失敗,整個map操作會失敗
console.log(results) // 拋出錯誤
處理超時操作
typescript
import { map } from 'radash'
async function mapWithTimeout<T, U>(
items: T[],
fn: (item: T) => Promise<U>,
timeout: number
): Promise<U[]> {
return map(items, async (item) => {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeout)
try {
const result = await Promise.race([
fn(item),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
)
])
clearTimeout(timeoutId)
return result
} catch (error) {
clearTimeout(timeoutId)
throw error
}
})
}
const urls = ['https://api.example.com/slow', 'https://api.example.com/fast']
const results = await mapWithTimeout(urls, async (url) => {
const response = await fetch(url)
return response.json()
}, 5000) // 5秒超時
處理重試邏輯
typescript
import { map } from 'radash'
async function mapWithRetry<T, U>(
items: T[],
fn: (item: T) => Promise<U>,
maxRetries: number = 3
): Promise<U[]> {
return map(items, async (item) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn(item)
} catch (error) {
if (attempt === maxRetries) {
throw error
}
// 指數退避
await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
}
}
})
}
const urls = ['https://api.example.com/unreliable1', 'https://api.example.com/unreliable2']
const results = await mapWithRetry(urls, async (url) => {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return response.json()
}, 3)
處理進度跟蹤
typescript
import { map } from 'radash'
async function mapWithProgress<T, U>(
items: T[],
fn: (item: T, index: number) => Promise<U>,
onProgress?: (completed: number, total: number) => void
): Promise<U[]> {
const results: U[] = []
for (let i = 0; i < items.length; i++) {
const result = await fn(items[i], i)
results.push(result)
if (onProgress) {
onProgress(i + 1, items.length)
}
}
return results
}
const tasks = ['task1', 'task2', 'task3', 'task4', 'task5']
const results = await mapWithProgress(tasks, async (task, index) => {
await new Promise(resolve => setTimeout(resolve, 1000))
return `Completed ${task}`
}, (completed, total) => {
console.log(`Progress: ${completed}/${total} (${Math.round(completed/total*100)}%)`)
})
處理條件映射
typescript
import { map } from 'radash'
const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
{ id: 3, name: 'Charlie', role: 'admin' }
]
const results = await map(users, async (user) => {
if (user.role === 'admin') {
// 管理員需要額外的權限檢查
const permissions = await fetch(`/api/users/${user.id}/permissions`)
const userPermissions = await permissions.json()
return {
...user,
permissions: userPermissions
}
} else {
// 普通用戶只需要基本信息
return {
...user,
permissions: ['read']
}
}
})
console.log(results)
處理嵌套數據
typescript
import { map } from 'radash'
interface Post {
id: number
title: string
authorId: number
}
interface Author {
id: number
name: string
email: string
}
async function enrichPosts(posts: Post[]): Promise<(Post & { author: Author })[]> {
return map(posts, async (post) => {
const authorResponse = await fetch(`/api/authors/${post.authorId}`)
const author = await authorResponse.json()
return {
...post,
author
}
})
}
const posts: Post[] = [
{ id: 1, title: 'First Post', authorId: 1 },
{ id: 2, title: 'Second Post', authorId: 2 },
{ id: 3, title: 'Third Post', authorId: 1 }
]
const enrichedPosts = await enrichPosts(posts)
console.log(enrichedPosts)
處理批量操作
typescript
import { map } from 'radash'
async function processBatch<T, U>(
items: T[],
batchSize: number,
fn: (batch: T[]) => Promise<U[]>
): Promise<U[]> {
const batches: T[][] = []
for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize))
}
const batchResults = await map(batches, fn)
return batchResults.flat()
}
const userIds = Array.from({ length: 100 }, (_, i) => i + 1)
const users = await processBatch(userIds, 10, async (batch) => {
const response = await fetch('/api/users/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: batch })
})
return response.json()
})
console.log(`Processed ${users.length} users`)
處理文件操作
typescript
import { map } from 'radash'
async function processFiles(filePaths: string[]) {
return map(filePaths, async (filePath) => {
const fs = await import('fs/promises')
const content = await fs.readFile(filePath, 'utf-8')
// 處理文件內容
const processed = content.toUpperCase()
// 寫入處理後的文件
const outputPath = filePath.replace('.txt', '.processed.txt')
await fs.writeFile(outputPath, processed)
return {
inputPath: filePath,
outputPath,
size: processed.length
}
})
}
const files = ['./file1.txt', './file2.txt', './file3.txt']
const results = await processFiles(files)
console.log(results)
注意事項
- 並發執行: 所有異步操作會並發執行
- 錯誤處理: 如果任何操作失敗,整個map操作會失敗
- 性能: 適合I/O密集型操作,不適合CPU密集型操作
- 內存: 所有結果會同時保存在內存中
- 順序: 結果數組的順序與輸入數組的順序相同
與其他方法的區別
Array.prototype.map()
: 同步操作,不支持異步Promise.all()
: 需要手動創建Promise數組map()
: radash提供的簡潔的異步映射方法
實際應用場景
- API調用: 批量獲取數據
- 文件處理: 批量處理文件
- 數據庫操作: 批量查詢或更新
- 圖像處理: 批量處理圖像
- 數據轉換: 批量轉換數據格式