完成后,Observables链发出相同的Observable

时间:2018-03-21 11:42:24

标签: typescript rxjs observable

我希望在rxjs中执行此操作:

  • 我有N个http来电;
  • 我想点击这些电话顺序;
  • 我想将每个调用的结果映射到InfoMessage的Observable流中;

非工作伪代码:

class InfoMessage {
  constructor(public message: string) {}
}

doAllRequests() : Observable<InfoMessage> {
    return Observable.create((obs: Observer<InfoMessage>) => {
      doRequest("http://test1.com").map((res: RxRequestResponse) => obs.next(new InfoMessage("request1 done")));
      doRequest("http://test2.com").map((res: RxRequestResponse) => obs.next(new InfoMessage("request2")));
      doRequest("http://test3.com").map((res: RxRequestResponse) => obs.next(new InfoMessage("request3")));
      obs.complete();
    });
  }

doRequest(url: string) : Observable<RxRequestResponse> {
  // use some http client which is wrapped in an Observable of type RxRequestResponse
}

doAllRequests().subscribe(next => console("Message: " + next.message));

更新马丁的建议答案: 你的答案似乎有效,但只有当我订阅第一个请求时才这样:

Observable.create((observer: Observer<InfoMessage>) => {
  doRequest("http://test1.com")
    .do(response => observer.next(new InfoMessage("request1 done")))
    .concatMap(() => doRequest("http://test2.com"))
    .do(response => observer.next(new InfoMessage("request2")))
    .concatMap(() => doRequest("http://test3.com"))
    .do(response => {
      observer.next(new InfoMessage("request3"));
      observer.complete();
    }).subscribe();
})

我真的想推迟订阅并将其留给doAllRequests()的调用者。有什么想法吗?

更新:Quentin建议的回答

该解决方案可以正常工作,并且对于我将要运行的大型脚本(具有大量请求),在代码冗长(或者更缺乏代码)方面可以更好地扩展。

由于这是我现在最终使用的那个,我正在改变我接受的答案。但马丁,我对此感到内疚。我还有一个赞成你...我们好吗?

2 个答案:

答案 0 :(得分:1)

如果每个HTTP呼叫独立于前一个呼叫的结果,您可以使用concatMap链接它们:

Observable.create((observer: Observer<InfoMessage>) => {
  doRequest("http://test1.com")
    .do(response => observer.next(new InfoMessage("request1 done")))
    .concatMap(() => doRequest("http://test2.com"))
    .do(response => observer.next(new InfoMessage("request2")))
    .concatMap(() => doRequest("http://test3.com"))
    .do(response => {
      observer.next(new InfoMessage("request3"));
      observer.complete();
    });
})

不要忘记你需要从你的函数中返回Observable.create并订阅它。

答案 1 :(得分:1)

由于您的doRequest()已经返回了一个可观察对象,为什么不尝试将所有请求组合在一起并将响应转换为单个流?您可以使用forkJoin:

doAllRequests() : Observable<InfoMessage> {
 return forkJoin(
  doRequest("http://test1.com"),
  doRequest("http://test2.com"),
  doRequest("http://test3.com")
 ).pipe(
  mergeMap((responsesArray: any[]) => from(responsesArray)),
  map((response: any) => new InfoMessage(response))
 );
}
this.doAllRequests().subscribe();