map
Execute async operations on each element in an array and return an array containing all results.
Basic Usage
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]
Syntax
typescript
function map<T, U>(
array: readonly T[],
fn: (item: T, index: number, array: readonly T[]) => Promise<U>
): Promise<U[]>
Parameters
array
(readonly T[]): The array to processfn
(function): Async mapping functionitem
(T): Current elementindex
(number): Index of current elementarray
(readonly T[]): Original array
Return Value
Returns a Promise that resolves to the mapped array.
Examples
Basic Async Mapping
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]
Handle Object Arrays
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) => {
// Simulate fetching product details
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)
Handle Concurrency Limits
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) // Maximum 3 concurrent requests
Handle Error Cases
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
})
// If any operation fails, the entire map operation fails
console.log(results) // Throws error
Handle Timeout Operations
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 second timeout
Handle Retry Logic
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
}
// Exponential backoff
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)
Handle Progress Tracking
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)}%)`)
})
Handle Conditional Mapping
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') {
// Admins need additional permission checks
const permissions = await fetch(`/api/users/${user.id}/permissions`)
const userPermissions = await permissions.json()
return {
...user,
permissions: userPermissions
}
} else {
// Regular users only need basic information
return {
...user,
permissions: ['read']
}
}
})
console.log(results)
Handle Nested Data
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)
Handle Batch Operations
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`)
Handle File Operations
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')
// Process file content
const processed = content.toUpperCase()
// Write processed file
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)
Notes
- Concurrent execution: All async operations execute concurrently
- Error handling: If any operation fails, the entire map operation fails
- Performance: Suitable for I/O-intensive operations, not CPU-intensive operations
- Memory: All results are stored in memory simultaneously
- Order: The order of the result array matches the input array order
Differences from Other Methods
Array.prototype.map()
: Synchronous operations, doesn't support asyncPromise.all()
: Requires manually creating Promise arraysmap()
: Concise async mapping method provided by radash
Practical Application Scenarios
- API calls: Batch data retrieval
- File processing: Batch file processing
- Database operations: Batch queries or updates
- Image processing: Batch image processing
- Data transformation: Batch data format conversion