如何使用 RxJS 在 Angular 6 中发出一系列 http 请求
Posted
技术标签:
【中文标题】如何使用 RxJS 在 Angular 6 中发出一系列 http 请求【英文标题】:How to make a sequence of http requests in Angular 6 using RxJS 【发布时间】:2019-05-02 19:02:13 【问题描述】:我一直在网上寻找解决方案,但找不到任何适合我的用户案例的解决方案。我正在使用 MEAN 堆栈(Angular 6)并且我有一个注册表单。我正在寻找一种方法来执行对 API 的多个 HTTP 调用,每个调用都依赖于前一个返回的结果。我需要看起来像这样的东西:
firstPOSTCallToAPI('url', data).pipe(
result1 => secondPOSTCallToAPI('url', result1)
result2 => thirdPOSTCallToAPI('url', result2)
result3 => fourthPOSTCallToAPI('url', result3)
....
).subscribe(
success => /* display success msg */ ,
errorData => /* display error msg */
);
我需要使用哪种 RxJS 运算符组合来实现这一点?一种可能的解决方案是嵌套多个订阅,但我想避免这种情况并使用 RxJS 做得更好。还需要考虑错误处理。
【问题讨论】:
是否定义了可观察的数量?还是代码必须是动态的? 你可以使用 flatMap 或 switchMap rguerin,我想灵活一点,不依赖于可观察对象的确切数量。 @JEY我尝试使用switchMap,但我收到一条错误消息“预期1-2个参数,但得到3个”。可以举个例子吗? 【参考方案1】:对于依赖于先前结果的调用,您应该使用concatMap
firstPOSTCallToAPI('url', data).pipe(
concatMap(result1 => secondPOSTCallToAPI('url', result1))
concatMap( result2 => thirdPOSTCallToAPI('url', result2))
concatMap(result3 => fourthPOSTCallToAPI('url', result3))
....
).subscribe(
success => /* display success msg */ ,
errorData => /* display error msg */
);
如果你的异步方法不依赖于前面异步调用的返回值,你可以使用
concat(method(),method2(),method3()).subscribe(console.log)
【讨论】:
正是我想要的!!!非常感谢,你结束了我的痛苦! 在上述情况下, concatMap 没有按照您的想法进行操作。您可以在这里轻松使用 mergeMap @FanCheung 它可以正常工作,但如果您将示例中的concatMap
替换为mergeMap
或switchMap
,它仍然可以工作。 concatMap
的 wait until complete
方面仅在您通过管道传输多个数据的 observable 时才明显,而 firstPOSTCallToAPI 仅传输单个事件,第二个、第三个和第四个调用也是如此
你这个美丽的人类!!让我摆脱了这里的束缚。谢谢!【参考方案2】:
我遇到了同样的问题,这是我的解决方案,使用 pipe
和 concatMap
作为数组获取开始时间和结束时间之间的时间段的序列数据。
这是我们有数组请求时的通用解决方案。
我为谁担心。
let currentReplayData = [];
let timerange = [[t1, t2], [t3, t4]]; // array of start and end time
from(timerange).pipe(
concatMap(time => <Observable<any>>this.dataService.getData(time[0],time[1]))
).subscribe(val =>
//console.log(val)
this.currentReplayData = this.currentReplayData.concat(val);
);
【讨论】:
【参考方案3】:MergeMap
正是你要找的东西
firstPOSTCallToAPI('url', data).pipe(
mergeMap(result1 => secondPOSTCallToAPI('url', result1)),
mergeMap(result2 => thirdPOSTCallToAPI('url', result2)),
mergeMap(result3 => fourthPOSTCallToAPI('url', result3)),
// ...
).subscribe(
success =>
// here you will get response of LAST request (fourthPOSTCallToAPI)
,
errorData => /* display error msg */
);
// I assume that
// secondPOSTCallToAPI, thirdPOSTCallToAPI and fourthPOSTCallToAPI
// returns obserwable eg. return this.http.get<Book>(apiUrl);
【讨论】:
【参考方案4】:import HttpClient from '@angular/common/http';
import Injectable from '@angular/core';
import Observable from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
@Injectable()
export class DataService
constructor(private http: HttpClient)
public requestDataFromMultipleSources(): Observable<any[]>
let response1 = this.http.get(requestUrl1);
let response2 = this.http.get(requestUrl2);
let response3 = this.http.get(requestUrl3);
return Observable.forkJoin([response1, response2, response3]);
The above example shows making three http calls, but in a similar way you can request as many http calls as required
import Component, OnInit from '@angular/core';
import DataService from "../data.service";
@Component(
selector: 'app-page',
templateUrl: './page.component.html',
styleUrls: ['./page.component.css']
)
export class DemoComponent implements OnInit
public responseData1: any;
public responseData2: any;
public responseData3: any;
constructor(private dataService: DataService)
ngOnInit()
this.dataService.requestDataFromMultipleSources().subscribe(responseList =>
this.responseData1 = responseList[0];
this.responseData2 = responseList[1];
this.responseData3 = responseList[1];
);
【讨论】:
【参考方案5】:让我在这里向您展示如何操作,假设我有很多要按顺序发送电子邮件的电子邮件:
sendEmails()
this.isLoading = true;
const calls = this.emails <<-- assume this contain an array of emails
.map(email => this.userEmailService.deliver(email: email, userId: 1242));
from(calls) <<-- make use of the from.
.pipe(
concatMap(res => res),
finalize(() => this.isLoading = false)
).subscribe(() => );
我希望这会有所帮助。
【讨论】:
【参考方案6】:试试这个,Angular 提供了一次调用多个 API 的功能。
forkJoin()
您将在array
中以与调用 API 相同的顺序获取数据。
例如:
forkJoin(request1, request2)
.subscribe(([response1, response2]) =>
你可以找到更多read
我还给了另一个answer。请检查一下,它也可能对您有所帮助。
【讨论】:
forkJoin
一次发送所有 AFAIK,使用 concat
确保前一个完成
感谢您的回复。我已经研究了 forkJoin,但它看起来不像一个可行的解决方案,因为我需要 request2 来使用从 request1 返回的响应数据。
这种情况下,forkJoin 不会使用。我建议检查第二个链接。它适用于你的情况。以上是关于如何使用 RxJS 在 Angular 6 中发出一系列 http 请求的主要内容,如果未能解决你的问题,请参考以下文章
Angular:如何使用 RXJS 6 调用 finally()
Angular/RxJS 6:如何防止重复的 HTTP 请求?