reduce
對數組中的每個元素執行異步歸約操作,累積結果。
基礎用法
typescript
import { reduce } from 'radash'
const numbers = [1, 2, 3, 4, 5]
const sum = await reduce(numbers, async (acc, num) => {
await new Promise(resolve => setTimeout(resolve, 100))
return acc + num
}, 0)
console.log(sum) // 15
語法
typescript
function reduce<T, U>(
array: readonly T[],
fn: (acc: U, item: T, index: number, array: readonly T[]) => Promise<U>,
initial: U
): Promise<U>
參數
array
(readonly T[]): 要處理的數組fn
(function): 異步歸約函數acc
(U): 累積值item
(T): 當前元素index
(number): 當前元素的索引array
(readonly T[]): 原數組
initial
(U): 初始值
返回值
返回一個Promise,解析為最終的累積結果。
示例
基本異步歸約
typescript
import { reduce } from 'radash'
const numbers = [1, 2, 3, 4, 5]
const sum = await reduce(numbers, async (acc, num) => {
await new Promise(resolve => setTimeout(resolve, 100))
return acc + num
}, 0)
console.log(sum) // 15
處理對象數組
typescript
import { reduce } from 'radash'
const users = [
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 35 }
]
const userStats = await reduce(users, async (acc, user) => {
// 模擬異步操作
await new Promise(resolve => setTimeout(resolve, 50))
return {
totalAge: acc.totalAge + user.age,
names: [...acc.names, user.name],
count: acc.count + 1
}
}, { totalAge: 0, names: [], count: 0 })
console.log(userStats)
// { totalAge: 90, names: ['Alice', 'Bob', 'Charlie'], count: 3 }
處理API調用累積
typescript
import { reduce } from 'radash'
const userIds = [1, 2, 3, 4, 5]
const userData = await reduce(userIds, async (acc, userId) => {
const response = await fetch(`/api/users/${userId}`)
const user = await response.json()
return {
...acc,
[userId]: user,
totalUsers: acc.totalUsers + 1
}
}, { totalUsers: 0 })
console.log(userData)
處理文件內容累積
typescript
import { reduce } from 'radash'
async function processFiles(filePaths: string[]) {
return reduce(filePaths, async (acc, filePath) => {
const fs = await import('fs/promises')
const content = await fs.readFile(filePath, 'utf-8')
return {
...acc,
[filePath]: content.length,
totalSize: acc.totalSize + content.length
}
}, { totalSize: 0 })
}
const files = ['./file1.txt', './file2.txt', './file3.txt']
const fileStats = await processFiles(files)
console.log(fileStats)
處理數據庫查詢累積
typescript
import { reduce } from 'radash'
async function aggregateUserData(userIds: number[]) {
return reduce(userIds, async (acc, userId) => {
// 模擬數據庫查詢
const userResponse = await fetch(`/api/users/${userId}`)
const user = await userResponse.json()
const postsResponse = await fetch(`/api/users/${userId}/posts`)
const posts = await postsResponse.json()
return {
...acc,
users: [...acc.users, user],
totalPosts: acc.totalPosts + posts.length,
averageAge: (acc.averageAge * acc.users.length + user.age) / (acc.users.length + 1)
}
}, { users: [], totalPosts: 0, averageAge: 0 })
}
const userIds = [1, 2, 3]
const aggregated = await aggregateUserData(userIds)
console.log(aggregated)
處理條件累積
typescript
import { reduce } from 'radash'
const transactions = [
{ id: 1, amount: 100, type: 'income' },
{ id: 2, amount: 50, type: 'expense' },
{ id: 3, amount: 200, type: 'income' },
{ id: 4, amount: 75, type: 'expense' }
]
const balance = await reduce(transactions, async (acc, transaction) => {
await new Promise(resolve => setTimeout(resolve, 10))
if (transaction.type === 'income') {
return acc + transaction.amount
} else {
return acc - transaction.amount
}
}, 0)
console.log('Final balance:', balance) // 175
處理復雜對象累積
typescript
import { reduce } from 'radash'
interface Product {
id: number
name: string
price: number
category: string
}
const products: Product[] = [
{ id: 1, name: 'Laptop', price: 999, category: 'electronics' },
{ id: 2, name: 'Phone', price: 599, category: 'electronics' },
{ id: 3, name: 'Book', price: 19, category: 'books' },
{ id: 4, name: 'Tablet', price: 399, category: 'electronics' }
]
const productAnalysis = await reduce(products, async (acc, product) => {
// 模擬異步分析
await new Promise(resolve => setTimeout(resolve, 50))
return {
...acc,
totalValue: acc.totalValue + product.price,
categories: {
...acc.categories,
[product.category]: (acc.categories[product.category] || 0) + 1
},
averagePrice: (acc.averagePrice * acc.count + product.price) / (acc.count + 1),
count: acc.count + 1
}
}, { totalValue: 0, categories: {}, averagePrice: 0, count: 0 })
console.log(productAnalysis)
處理錯誤累積
typescript
import { reduce } from 'radash'
const operations = [
{ id: 1, shouldFail: false },
{ id: 2, shouldFail: true },
{ id: 3, shouldFail: false }
]
const results = await reduce(operations, async (acc, operation) => {
try {
if (operation.shouldFail) {
throw new Error(`Operation ${operation.id} failed`)
}
await new Promise(resolve => setTimeout(resolve, 100))
return {
...acc,
successful: [...acc.successful, operation.id],
totalProcessed: acc.totalProcessed + 1
}
} catch (error) {
return {
...acc,
failed: [...acc.failed, { id: operation.id, error: error.message }],
totalProcessed: acc.totalProcessed + 1
}
}
}, { successful: [], failed: [], totalProcessed: 0 })
console.log(results)
處理進度跟蹤
typescript
import { reduce } from 'radash'
async function processWithProgress<T, U>(
items: T[],
fn: (acc: U, item: T, index: number) => Promise<U>,
initial: U,
onProgress?: (completed: number, total: number) => void
): Promise<U> {
let result = initial
for (let i = 0; i < items.length; i++) {
result = await fn(result, items[i], i)
if (onProgress) {
onProgress(i + 1, items.length)
}
}
return result
}
const tasks = ['task1', 'task2', 'task3', 'task4', 'task5']
const result = await processWithProgress(
tasks,
async (acc, task, index) => {
await new Promise(resolve => setTimeout(resolve, 1000))
return [...acc, `Completed ${task}`]
},
[],
(completed, total) => {
console.log(`Progress: ${completed}/${total} (${Math.round(completed/total*100)}%)`)
}
)
console.log(result)
處理嵌套數據累積
typescript
import { reduce } from 'radash'
interface Post {
id: number
title: string
authorId: number
tags: string[]
}
const posts: Post[] = [
{ id: 1, title: 'First Post', authorId: 1, tags: ['javascript', 'react'] },
{ id: 2, title: 'Second Post', authorId: 2, tags: ['typescript', 'vue'] },
{ id: 3, title: 'Third Post', authorId: 1, tags: ['javascript', 'node'] }
]
const postAnalysis = await reduce(posts, async (acc, post) => {
// 模擬獲取作者信息
const authorResponse = await fetch(`/api/authors/${post.authorId}`)
const author = await authorResponse.json()
return {
...acc,
authors: {
...acc.authors,
[author.id]: {
...author,
postCount: (acc.authors[author.id]?.postCount || 0) + 1
}
},
tags: {
...acc.tags,
...post.tags.reduce((tagAcc, tag) => ({
...tagAcc,
[tag]: (acc.tags[tag] || 0) + 1
}), {})
},
totalPosts: acc.totalPosts + 1
}
}, { authors: {}, tags: {}, totalPosts: 0 })
console.log(postAnalysis)
處理批量操作累積
typescript
import { reduce } from 'radash'
async function processBatchWithAccumulation<T, U>(
items: T[],
batchSize: number,
fn: (acc: U, batch: T[]) => Promise<U>,
initial: U
): Promise<U> {
const batches: T[][] = []
for (let i = 0; i < items.length; i += batchSize) {
batches.push(items.slice(i, i + batchSize))
}
return reduce(batches, fn, initial)
}
const userIds = Array.from({ length: 100 }, (_, i) => i + 1)
const userStats = await processBatchWithAccumulation(
userIds,
10,
async (acc, batch) => {
const response = await fetch('/api/users/batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ids: batch })
})
const users = await response.json()
return {
...acc,
totalUsers: acc.totalUsers + users.length,
averageAge: (acc.averageAge * acc.batchCount + users.reduce((sum, u) => sum + u.age, 0)) / (acc.batchCount + 1),
batchCount: acc.batchCount + 1
}
},
{ totalUsers: 0, averageAge: 0, batchCount: 0 }
)
console.log(userStats)
注意事項
- 順序執行: 異步操作按順序執行,不是並發的
- 錯誤處理: 如果任何操作失敗,整個reduce操作會失敗
- 性能: 適合需要累積結果的場景,不適合獨立操作
- 內存: 累積值會持續增長,注意內存使用
- 初始值: 必須提供初始值
與其他方法的區別
Array.prototype.reduce()
: 同步操作,不支持異步reduce()
: radash提供的異步歸約方法map()
: 處理獨立操作,reduce()
處理累積操作
實際應用場景
- 數據聚合: 累積統計數據
- 文件處理: 累積文件內容或統計信息
- 數據庫操作: 累積查詢結果
- API調用: 累積多個API的響應數據
- 業務邏輯: 累積復雜的業務計算結果