Angular 6:将 Observable 响应传递给另一个 Observable

Posted

技术标签:

【中文标题】Angular 6:将 Observable 响应传递给另一个 Observable【英文标题】:Angular 6: Passing Observable response to another Observable 【发布时间】:2019-01-07 04:07:32 【问题描述】:

我在使用 angular typescript 中的 observable 获取 Web API 输出时遇到问题。

我想获取第一个 observable 返回的值,然后将其值传递给另一个 observable。到目前为止,这就是我所写的。

let output: any;
let output2: any;

_httpClient.get('http://localhost:5000/api/mycontroller')
  .subscribe((output_1) => 
    output = output_1;
  );

alert(output);

_httpClient.get('http://localhost:5000/api/mycontroller2'+output)
  .subscribe((output_2) => 
    output2 = output_2;        
  );
alert(output2);

我在每个订阅的 observable 下方放置了一个警报函数,以检查每个响应返回的输出。

但是当我执行它并检查警告框中的输出时,它给每个都提供了未定义的值。

如何强制 observable 提供来自我的 Web API 的输出?

【问题讨论】:

【参考方案1】:

您可以使用诸如switchMap 之类的运算符,根据文档“映射到可观察对象,完成先前的内部可观察对象,发出值”。使用switchMap 它将切换到第二个HttpClient 调用映射第一个可观察对象,当第一个HttpClient 调用的源发出时。如果执行了新的初始/外部请求,它将取消进行中/进行中的请求。

请记住,alert() 语句的设置方式将无法正常工作,因为 alert() 将在请求完成之前执行,因此 undefined。您需要在subscribe 中执行alert() 或类似操作,或使用do/tap 等运算符来确保实际返回数据。

import  switchMap  from 'rxjs/operators';

_httpClient.get('http://localhost:5000/api/mycontroller')
  .pipe(
    switchMap(output => _httpClient.get('http://localhost:5000/api/mycontroller2' + output))
  )
  .subscribe(output2 => alert(output2));

如果您需要将输出保存到某个本地类属性,您可以利用do/tap 在数据返回/映射/处理之前/之后执行操作。

import  switchMap, tap  from 'rxjs/operators';

_httpClient.get('http://localhost:5000/api/mycontroller')
  .pipe(
    tap(output => 
        console.log(output);
        this.output = output;            
    ),
    switchMap(output => _httpClient.get('http://localhost:5000/api/mycontroller2' + output)),
    tap(output2 => 
        console.log(output2);
        this.output2 = output2;            
    )
  )
  .subscribe(output2 => alert(output2));

【讨论】:

实际上,switchMap 的作用与确保第一个请求完成完全相反。如果第一个请求在下一次发射之前没有完成,它实际上会被取消以支持第二个请求。 我会更新答案的语言。无论哪种方式,请求者都需要一个简单的运算符来将连续的 HttpClient 调用链接在一起,这就是 switchMap 所展示的。如果您想展示带有 mergeMap、concatMap、exhaustMap 等的示例,请随意这样做。 @ggradnig 如果您认为这是错误的,一个更有帮助的回应是展示其他方法来顺序进行HttpClient 调用,甚至使用上下文中的运算符处理第一个HttpClient 调用中的错误请求者的问题。谢谢! 嗨,Alex,anwser 当然是对的,但是如果理解不正确,有关 switchMap 的细微细节可能会导致问题。例如,如果在 switchMap 语句之后执行写操作,它将被取消,从而使 API 调用的结果永远丢失。无论如何,您也可以使用 mergeMap 进行顺序调用,因此也可以提及此替代方案。 @AlexanderStaroselsky:如果我需要在第二个 API 调用中重复执行操作,如 switchMap(output => _httpClient.get('localhost:5000/api/mycontroller2' + output[i])) , output[i] 是第一个 API 调用发出的值吗?我的意思是如何根据第一次 api 调用传递的值重复 switchMap 操作?【参考方案2】:

为了完整接受答案,还应提及switchMap 的其他替代方案。

switchMap 相比,mergeMap(也称为flatMap)运算符将不会在“外部 observable”在“inner observable”完成之前第二次发出时被取消.这在HttpClient.get 的情况下可能并不重要,因为它通常只发出一次,因此永远不会再次触发内部可观察对象。

但是,在继续使用 RxJS 运算符时,尤其是在处理顺序数据流时,请注意 switchMapmergeMap 之间的区别。

【讨论】:

mergeMap确实不是取消http请求,而是导致多余的http请求,因为它会用旧值发出外部请求,当它得到新值时会发出另一个请求。

以上是关于Angular 6:将 Observable 响应传递给另一个 Observable的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Angular 将 Observable 用于 HttpClient?

Angular 6 - 从 observable 获取数据我做错了啥?

无法使用 Observable、Firebase (Angular 6) 为 var 赋值

无法在 RxJs 6 和 Angular 6 中使用 Observable.of

Angular/RxJS 6:如何防止重复的 HTTP 请求?

Angular 6 router.events.filter 'filter' 不存在于类型'Observable<Event>'