You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用array.reduce返回Promise数组以实现异步并行执行?

问题描述

原本用array.map遍历数组返回Promise数组,现在要改用array.reduce实现,但直接替换后耗时暴涨近10倍——因为异步调用变成了串行执行。我想通过reduce生成一个可以后续用Promise.all()批量解析的Promise数组,以下是模拟场景和尝试过的方案,请指导正确实现方式:

interface IUser { name: string; balance: number | undefined; }

let user1 = { name: 'user1', balance: undefined }
let user2 = { name: 'user2', balance: undefined }
let user3 = { name: 'user3', balance: undefined }
const users = [user1, user2, user3]

async function calculateBalance(user: IUser): Promise<IUser> {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  user.balance = Math.floor(Math.random() * 5000) + 1000;

  return user;
}

async function processUsers() {
  return users.reduce(async (acc, currUser, index) => {
    return [ ...acc, calculateBalance(currUser) ] // not working
    return acc.push(calculateBalance(currUser)) // Argument of type 'Promise<IUser>' is not assignable to parameter of type 'never'
    return acc.concat(calculateBalance(currUser)) // Same above
  }, [])
}

const processedUsersArray = await processUsers();
await Promise.all(processedUsersArray) // Desired thing for the sake of performance

问题根源

你犯的核心错误是给reduce的回调加了async,导致每一轮迭代的acc不再是普通数组,而是Promise对象。你试图对Promise用数组的展开、push、concat方法,自然会触发类型错误,同时还意外把异步调用变成了串行——因为每一轮都要等上一轮的Promise resolve才能继续。

正确实现

要达到和map一样的并行效果,reduce不需要异步回调,直接同步收集Promise即可。因为calculateBalance被调用时就会立即启动异步逻辑,我们只需要把这些已经在运行的Promise收集到数组里,最后用Promise.all等待全部完成就行:

interface IUser { name: string; balance: number | undefined; }

let user1 = { name: 'user1', balance: undefined }
let user2 = { name: 'user2', balance: undefined }
let user3 = { name: 'user3', balance: undefined }
const users = [user1, user2, user3]

async function calculateBalance(user: IUser): Promise<IUser> {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  user.balance = Math.floor(Math.random() * 5000) + 1000;
  return user;
}

function processUsers() {
  // 去掉async,同步收集Promise
  return users.reduce((acc, currUser) => {
    acc.push(calculateBalance(currUser));
    return acc;
  }, [] as Promise<IUser>[]); // 显式指定初始值类型,解决TS类型推断问题
}

// 调用示例
(async () => {
  const promiseArray = processUsers();
  const result = await Promise.all(promiseArray);
  console.log(result); // 5秒后全部返回,和map效果一致
})();

关键说明

  • 并行逻辑的核心:calculateBalance被调用时就会立即执行异步操作(启动5秒定时器),reduce只是把这些Promise收集起来,所有异步操作是同时开始的,总耗时还是5秒左右,不会串行。
  • 类型处理:[] as Promise<IUser>[]是为了让TypeScript正确识别初始数组的类型,避免类型报错。
  • 为什么之前串行:加了async的回调会把每一轮的返回值包装成Promise,reduce会等待上一轮的Promise resolve后才进入下一轮,导致异步操作一个接一个执行,总耗时变成5*3=15秒。

内容的提问来源于stack exchange,提问作者anileates

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:57:39