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

如何在async/await函数中应用DRY原则且避免过度性能开销?

优化异步重复代码提取后的性能问题

问题背景

有两个包含大量重复异步逻辑的函数,提取共享函数后,getAllMessageStats的执行时间暴涨至原来的3倍以上,尤其在消息量上千时表现明显。核心问题是提取共享函数后,串行的await导致异步请求无法并行处理,但又不想保留重复代码,寻求优雅的解决方案。

原函数实现

函数1:getAllMessageStats

const getAllMessageStats = async (userId: string) => {
  const messageIds = await getUserMessageIds(userId);
 
  let messagesRead = 0;
  let reactionsTotal = 0;
  const moreStats = [];

  for (const messageId of messageIds) {
    const message = await getMessage(messageId);

    if (message.read) messagesRead++;
    reactionsTotal += message.reactions;

    const otherStats = [];
    for (const otherDataId of message.otherDataIds) {
      const otherData = await getOtherData(otherDataId)
      otherStats.push(doLotsOfOtherCalcs(otherData));
    }
    moreStats.push(otherStats);
  }

  return {
    messagesRead,
    reactionsTotal,
    moreStats
  }
};

函数2:getMessageStats

const getMessageStats = async (messageId: string) => {
  const message = await getMessage(messageId);
  const otherStats = [];
  for (const otherDataId of message.otherDataIds) {
    const otherData = await getOtherData(otherDataId)
    otherStats.push(doLotsOfOtherCalcs(otherData));
  }
  const miscData = await getMiscData(messageId);

  return {
    read: message.read,
    reactions: message.reactions,
    otherStats,
    miscData
  }
};

尝试的共享函数实现(性能暴跌)

const sharedFunction = async (messageId: string) => {
  const message = await getMessage(messageId);
  const otherStats = [];
  for (const otherDataId of message.otherDataIds) {
    const otherData = await getOtherData(otherDataId)
    otherStats.push(doLotsOfOtherCalcs(otherData));
  }
  return {
    read: message.read,
    reactions: message.reactions,
    otherStats
  }
};

const getMessageStats = async (messageId: string) => {
  const { read, reactions, otherStats } = await sharedFunction(messageId);
  const miscData = await getMiscData(messageId);
  return {
    read,
    reactions,
    otherStats,
    miscData
  }
};

const getAllMessageStats = async (userId: string) => {
  const messageIds = await getUserMessageIds(userId);
 
  let messagesRead = 0;
  let reactionsTotal = 0;
  const moreStats = [];

  for (const messageId of messageIds) {
    const { read, reactions, otherStats } = await sharedFunction(messageId);

    if (read) messagesRead++;
    reactionsTotal += reactions;
    moreStats.push(otherStats);
  }

  return {
    messagesRead,
    reactionsTotal,
    moreStats
  }
};

解决方案

性能暴跌的核心原因是串行执行异步请求:原函数中虽然也是串行,但提取共享函数后,每个sharedFunction内部的getMessage和getOtherData都是串行,且外层循环也是逐个await,完全没有并行空间。可以通过以下两种方式优化,同时保留代码复用性:

1. 并行化批量处理请求

将循环中的串行await改为Promise.all,同时处理多个异步请求,大幅减少等待时间。可以拆分共享逻辑为“单消息处理逻辑”,然后在批量场景下并行调用:

// 保留共享的单消息处理逻辑
const processSingleMessage = async (messageId: string) => {
  const message = await getMessage(messageId);
  // 并行获取所有otherData,而非串行
  const otherDataList = await Promise.all(
    message.otherDataIds.map(id => getOtherData(id))
  );
  const otherStats = otherDataList.map(doLotsOfOtherCalcs);
  return {
    read: message.read,
    reactions: message.reactions,
    otherStats
  };
};

// 优化getMessageStats
const getMessageStats = async (messageId: string) => {
  const messageStats = await processSingleMessage(messageId);
  const miscData = await getMiscData(messageId);
  return {
    ...messageStats,
    miscData
  };
};

// 优化getAllMessageStats:并行处理所有消息
const getAllMessageStats = async (userId: string) => {
  const messageIds = await getUserMessageIds(userId);
  // 并行处理所有消息,而非逐个await
  const messageStatsList = await Promise.all(
    messageIds.map(id => processSingleMessage(id))
  );

  // 同步聚合统计数据
  const { messagesRead, reactionsTotal, moreStats } = messageStatsList.reduce(
    (acc, stats) => {
      if (stats.read) acc.messagesRead++;
      acc.reactionsTotal += stats.reactions;
      acc.moreStats.push(stats.otherStats);
      return acc;
    },
    { messagesRead: 0, reactionsTotal: 0, moreStats: [] }
  );

  return {
    messagesRead,
    reactionsTotal,
    moreStats
  };
};

2. 进一步优化:批量获取数据(如果后端支持)

如果后端提供批量接口(比如getMessagesByIds、getOtherDataByIds),可以进一步减少请求次数,这是性能优化的终极方案:

// 共享的统计计算逻辑(同步函数,纯计算)
const calculateMessageStats = (message: Message, otherDataList: OtherData[]) => {
  const otherStats = otherDataList.map(doLotsOfOtherCalcs);
  return {
    read: message.read,
    reactions: message.reactions,
    otherStats
  };
};

// 优化getAllMessageStats:批量获取所有数据
const getAllMessageStats = async (userId: string) => {
  const messageIds = await getUserMessageIds(userId);
  // 批量获取所有消息
  const messages = await getMessagesByIds(messageIds);
  // 收集所有需要的otherDataId
  const allOtherDataIds = messages.flatMap(msg => msg.otherDataIds);
  // 批量获取所有otherData
  const otherDataMap = new Map(
    (await getOtherDataByIds(allOtherDataIds)).map(data => [data.id, data])
  );

  // 同步计算每个消息的统计
  const messageStatsList = messages.map(message => {
    const otherDataList = message.otherDataIds.map(id => otherDataMap.get(id)!);
    return calculateMessageStats(message, otherDataList);
  });

  // 聚合结果
  return messageStatsList.reduce(
    (acc, stats) => {
      if (stats.read) acc.messagesRead++;
      acc.reactionsTotal += stats.reactions;
      acc.moreStats.push(stats.otherStats);
      return acc;
    },
    { messagesRead: 0, reactionsTotal: 0, moreStats: [] }
  );
};

// 优化getMessageStats:复用计算逻辑
const getMessageStats = async (messageId: string) => {
  const message = await getMessage(messageId);
  const otherDataList = await Promise.all(
    message.otherDataIds.map(id => getOtherData(id))
  );
  const messageStats = calculateMessageStats(message, otherDataList);
  const miscData = await getMiscData(messageId);
  return {
    ...messageStats,
    miscData
  };
};

关键优化点

  • 并行请求:用Promise.all替代串行await,同时发起多个异步请求,减少总等待时间。
  • 拆分逻辑:将异步数据获取和同步计算分离,共享纯计算逻辑,避免异步逻辑的重复。
  • 批量请求:如果后端支持,尽量使用批量接口减少网络请求次数,这对性能提升最显著。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 05:44:52