【问题标题】:Cannot get result of first HTTP request using RxJS' switchMap无法使用 RxJS 的 switchMap 获取第一个 HTTP 请求的结果
【发布时间】:2020-11-16 08:20:33
【问题描述】:

我正在尝试发出 2 个 HTTP 请求,在第一次调用中我尝试创建一条记录,然后根据其结果(来自 API 方法的响应)我想执行或省略第二次调用来更新另一个数据。但是,虽然我可以在catchError 块中捕获错误,但我无法在第一次调用的 switchMap 方法中得到响应。那么,根据给定的场景,这个实现有什么问题呢?以及如何获得第一个结果的响应并根据第一个响应继续或不继续第二个调用?

let result;
let statusCode;

this.demoService.create(...).pipe(
    catchError((err: any) => { ... }),
    switchMap(response => {

    // I am trying to get the response of first request at here
    statusCode = response.statusCode;

    if(...){
        return this.demoService.update(...).pipe(
            catchError((err: any) => { ... }),
            map(response => {
            return {
                result: response
              }
          }
        )
      )}
    }
  ))
  .subscribe(result => console.log(result));

【问题讨论】:

  • 您能否尝试在 catchError 之前在您的管道上添加“tap(console.log)”,以确认服务的创建是否返回数据以及是否记录任何内容? tap 在 rxjs/operators 下导入
  • 你所说的“我无法在switchMap”中得到回复是什么意思?您无法读取statusCode 属性吗?它会抛出任何错误吗?您确定该属性在响应中可用吗?请详细说明。
  • @MichaelD 我想要做的是获取第一个调用(创建)的响应并根据其结果,执行第二个调用(更新)或中断(如果有错误我认为switchMap 不执行其他人,但如果没有错误,我可能想根据响应值中断)。当然我还需要得到第二次调用的响应。
  • @PragDopravy:你现在到底有什么不能做的?
  • @KShewengger 我试过tap(response => { console.log(response); debugger; }),,但代码没有打到那里并打到switchMap块(之后它仍然没有打到tap()块)。那么,我的用法有什么错误吗?

标签: javascript angular typescript rxjs switchmap


【解决方案1】:

这个问题对我来说仍然很模糊。我将发布一个更通用的答案以澄清一些事情

有很多事情需要注意

  1. 当一个 observable 发出 error 通知时,该 observable 被认为是关闭的(除非再次触发),并且不会触发以下依赖于 next 通知的运算符。如果您希望在switchMap 中捕获错误通知,您可以从catchError 返回一个next 通知。使用 RxJS of 函数的 catchError(error => of(error)) 之类的东西。然后通知将被以下switchMap 捕获。

  2. 必须switchMap返回一个observable,不管你的情况如何。在这种情况下,如果您不希望在条件失败时返回任何内容,您可以返回 RxJS NEVER。但是,如果您希望发出可以被订阅 next 回调捕获的消息,您可以使用 RxJS of 函数。将return NEVER 替换为return of('Some message that will be emitted to subscription's next callback');

import { of, NEVER } from 'rxjs';
import { switchMap, catchError, map } from 'rxjs/operators';

this.demoService.create(...).pipe(
  catchError((err: any) => { ... }),
  switchMap(response => {
    statusCode = response.statusCode;

    if (someCondition) {
      return this.demoService.update(...).pipe(  // emit `update()` when `someCondition` passes
        catchError((err: any) => { ... }),
        map(response => ({ result: response }))
      );
    }
    // Show error message
    return NEVER;               // never emit when `someCondition` fails
  }
)).subscribe({
  next: result => console.log(result),
  error: error => console.log(error)
});

【讨论】:

  • 非常感谢您的帮助。几个小时后我会检查并通知你结果。顺便说一句,投票赞成这种好方法;)如果有需要,您可以在接下来的几个小时内更新您的解决方案,我将无法尝试。
  • 我尝试了这种方法,发现我需要处理第一个 catchError() 块中的响应。然后我在该块中返回err,但我无法在switchMap 中将它作为response 变量。那么,我应该在switchMap 块中获取从catchError 返回的值吗?
  • 答案点 1 中已经解决了该问题的解决方案。
  • 我也可以在catchError 块中应用一些逻辑吗?因为我只在该块中捕获了一些响应,但我不确定它是否是处理此类逻辑的正确位置。有什么想法吗?
  • 您可以处理 catchError 块中的逻辑。但这取决于逻辑。
【解决方案2】:

你可以用iif实现

this.demoService
   .create(...)
   .pipe(
     // tap first to be sure there's actually a response to process through
     tap(console.log),

     // You can use any condition in your iif, "response.user.exists" is just a sample
     // If the condition is true, it will run the run the update$ observable
     // If not, it will run the default$
     // NOTE: All of them must be an observable since you are inside the switchMap
     switchMap(response => 
      iif(() => 
        response.user.exists, 
        this.demoService.update(response.id),    // Pass ID 
        of('Default Random Message')
      )
     ),
     catchError((err: any) => { ... })
   );

【讨论】:

  • 非常感谢您的帮助。几个小时后我会检查并通知你结果。顺便说一句,投票赞成这种好方法;)
  • 非常感谢您的帮助。几个小时后我会检查并通知你结果。顺便说一句,投票赞成这种好方法;)如果有需要,您可以在接下来的几个小时内更新您的解决方案,我将无法尝试。
  • 我只是尝试使用这个方法。 1. 我需要将id 值传递给update$ observable (this.demoService.update(...))。我怎么能通过呢? 2. 如何通过在 iif 块内定义 update$default$ 变量内容(例如 this.demoService.update(...))来使用此 iif
  • @PragDopravy 更新了我的答案,您实际上仍然可以使用原始函数,而无需将它们分配到变量中,您也可以从那里传递数据。希望它有所帮助:)
  • 非常感谢您的 lins 帮助。实际上,该方法也是一个可观察的方法,我不确定是否应该再次使用它们的管道、映射、switchMap、catchError 块定义这些方法?在那种情况下,我看到它会是缠结的意大利面 :) 那么,您能否请this.demoService.update(response.id) 的方法主体和定义位置?对不起,但我真的很新,最近几天我也被这个问题纠缠在一起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-07
  • 2020-12-13
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多