Skip to content

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)

注意事项

  1. 顺序执行: 异步操作按顺序执行,不是并发的
  2. 错误处理: 如果任何操作失败,整个reduce操作会失败
  3. 性能: 适合需要累积结果的场景,不适合独立操作
  4. 内存: 累积值会持续增长,注意内存使用
  5. 初始值: 必须提供初始值

与其他方法的区别

  • Array.prototype.reduce(): 同步操作,不支持异步
  • reduce(): radash提供的异步归约方法
  • map(): 处理独立操作,reduce() 处理累积操作

实际应用场景

  1. 数据聚合: 累积统计数据
  2. 文件处理: 累积文件内容或统计信息
  3. 数据库操作: 累积查询结果
  4. API调用: 累积多个API的响应数据
  5. 业务逻辑: 累积复杂的业务计算结果

Released under the MIT License.