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

如何用RxJS通过forEach模式在单个Action中执行多API请求

问题描述

我是React新手,负责修改一个已实现多API调用的现有应用。项目中使用的模式如下例所示:当触发类型为CaseReducerActions<CaseReducers>的mapperActions.selectPolygon Action时,以下代码会执行,调用fetchPolygon函数从AWS Lambda异步获取数据,返回结果由fetchPolygonCompleted函数处理。

let fetchPolygonStatsEpic = (action$: any, state$: StateObservable<RootState>) => action$.pipe(
  ofType(
    mapperActions.selectPolygon.type,
    mapperActions.alterQueryIndexname.type,
  ),
  filter(()  => state$.value.mapper.selectedPolygon !== undefined),
  switchMap(() =>
    concat(
      of(globalActions.startLoading('polygon')),
      fetchPolygon(state$.value.mapper).pipe(
        map(result => mapperActions.fetchPolygonCompleted(result)),
        catchError(e => of(globalActions.errorOccurred(e.message)))),
      of(globalActions.stopLoading('polygon')),
    )
  )
)

我需要实现的修改如下:
定义了类型Framework:

export type Framework = {
....
}

以及该类型的集合:

export const frameworks: {[framework: string]: Framework} = {
  liveng0: {
    ...
  },
  liveng1: {
    ...
  },
  habmosCairngorms: {
    ...
  },
  spaceintCairngorms: {
    ...
  }
}

还有一个根据指定Framework获取数据的API方法:

export let fetchHabitats = (requiredFramework: Framework): Observable<FrameworkHabitats> => {
...
}

当触发类型为CaseReducerActions<CaseReducers>的mapperActions.initialise Action时,需要执行一段代码,依次对上述4个Framework类型执行4次异步API调用并处理数据。我通过复制粘贴API调用的简单方式已实现需求,但需要改用遍历模式处理每个Framework,同时保持每个API调用的原子性,且仍能通过单个Action触发所有4次调用。

优化实现方案

可以通过以下方式重构代码,消除重复逻辑同时保留原有的顺序执行、原子性特性:

// 封装复用的请求处理逻辑,避免重复编写pipe/map/catchError
const createHabitatFetchStream = (framework: Framework) => {
  return fetchHabitats(framework).pipe(
    map(result => mapperActions.fetchHabitatsCompleted(result)),
    catchError(e => of(globalActions.errorOccurred(e.message)))
  );
};

let fetchHabitatsEpic = (action$: any, state$: StateObservable<RootState>) => action$.pipe(
  ofType(mapperActions.initialise.type),
  switchMap(() => {
    // 将对象形式的frameworks转为数组,方便遍历生成请求流
    const frameworkRequestStreams = Object.values(frameworks).map(createHabitatFetchStream);
    
    // 用concat串联加载状态和所有请求流,保持顺序执行
    return concat(
      of(globalActions.startLoading('habitats')),
      ...frameworkRequestStreams, // 展开所有请求流数组
      of(globalActions.stopLoading('habitats'))
    );
  })
);

核心逻辑说明

  • Object.values(frameworks):把键值对形式的frameworks转换为Framework实例数组,统一遍历处理。
  • 封装createHabitatFetchStream:将单个请求的业务逻辑抽离,后续修改请求处理逻辑只需维护这一处代码。
  • ...frameworkRequestStreams:通过展开运算符将数组中的Observable依次传入concat,确保请求按顺序执行(前一个请求完成后才触发下一个),保留原有的原子性。
  • 整体流程和原代码一致:触发initialise Action后,先发送加载开始动作,依次执行所有请求,最后发送加载结束动作,错误处理逻辑也完全保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:15:52