在单个@ngrx/effect中按顺序执行多个Http请求的实现咨询
@ngrx Effect 串行请求实现方案
你当前的concatMap用法存在错误,concatMap要求传入的是一个返回Observable的回调函数,而非直接传入Observable数组。要实现四个请求按串行顺序执行、前一个请求完成后才触发下一个,可按以下方式修改:
processOrder$ = createEffect(() => this.actions$.pipe( ofType(OrderActions.PROCESS_ORDER), // concatMap接收触发action,返回串行执行的Observable流 concatMap((action) => // concat按传入顺序依次订阅内部Observable,前一个complete后才订阅下一个 concat( this.service.addCrust(), this.service.addTopings(), this.service.sendToCook(), this.service.checkOut() ).pipe( // 只保留最后一个checkOut接口的返回值,需全量结果可替换为toArray() last(), map((checkOutResult) => OrderActions.processOrderSuccess({ data: checkOutResult })), // 任意步骤出错直接终止后续请求,触发失败Action catchError((error) => of(OrderActions.processOrderFailure({ error: error.message }))) ) ) ) );
核心逻辑说明
- 执行规则:
concat会严格按照传入顺序执行请求,任意一个请求未完成前,后续请求不会发起,完全匹配按顺序处理的需求。 - 结果处理规则:
- 需获取所有请求的返回值时,将
last()替换为toArray(),会将四个请求的返回值按执行顺序组装为数组传入后续map - 仅需最后一步
checkOut的返回结果时,保留last()即可 - 任意一步请求抛出错误都会直接进入
catchError,可在失败Action中处理错误提示、状态回滚等逻辑
- 需获取所有请求的返回值时,将
特殊场景适配
如果前一个请求的返回值需要作为后一个请求的入参,不能直接用concat,要改用concatMap链式调用,示例如下:
concatMap((action) => this.service.addCrust().pipe( concatMap((crustRes) => this.service.addTopings(crustRes.id)), concatMap((topingsRes) => this.service.sendToCook(topingRes.list)), concatMap((cookRes) => this.service.checkOut(cookRes.orderNo)), map((checkOutResult) => OrderActions.processOrderSuccess({ data: checkOutResult })), catchError((error) => of(OrderActions.processOrderFailure({ error: error.message }))) ) )
注意:需保证service方法返回的是冷Observable(如Angular HttpClient默认返回的类型),如果是热Observable会提前触发请求,无法实现串行效果。
内容的提问来源于stack exchange,提问作者3xGuy
相关产品推荐
相关产品推荐

