有更好的顺序调用不同的可观察调用的方法吗?

时间:2019-02-13 01:12:21

标签: angular typescript rxjs

我有两种API方法:

  • POST / articles / {id} /修订
  • GET / articles / {id}

发布到修订的结果是修订文档,其中包括对文章对象进行更改之前/之后。这不是文章对象。

这些对应于我的Angular应用程序中的以下方法:

  • this.endpoint.articles.revise(article.id, revisionParams);
  • this.endpoint.articles.getById(article.id);

分别返回Observable<ArticleRevision>Observable<Article>

当我修改文档时,我想提取具有更改的文档的更新副本。目前,我可以通过执行以下操作来实现此目标:

private reviseArticle(article: article, revisionParams: ArticleRevisionParams): Observable<Article> {
    return this.endpoint.articles.revise(article.id, revisionParams)
        .expand(r => this.endpoint.articles.getById(article.id))
        .pipe(take(2))
        .last();
}

从描述或expand看来,此方法更像是一种技巧,而不是解决方案:

  

递归调用提供的函数。

我尝试使用concat,但发现它需要使用相同类型的可观察对象,在我的情况下,这有点令人不快。我是在滥用expand,还是有一种更好的(更正确的)方式来顺序链接不同的可观察对象?

P.S。我标记了Angular,以防rxjs的Angular捆绑风格与常规rxjs略有不同。如果不属于它,请随时将其删除。

2 个答案:

答案 0 :(得分:2)

要在不使用容器类型的情况下完成此操作,可以利用forkJoin运算符。

这个想法是构成中间结果,以便它由您的第一个请求的结果以及第二个请求的结果(取决于您的第一个请求)组成。此组合的一部分要求您将第一个请求结果转换为可观察的结果,您可以使用of进行此操作。

随后,您可以从单个结果数组参数(即([reviseResult, getByIdResult]) => { ... })解构每个请求的响应。

const { forkJoin, of } = rxjs;
const { switchMap } = rxjs.operators;

function revise(id, params) {
  return of({ id, params, operation: 'revise' });
}

function getById(id) {
  return of({ id, operation: 'getById' });
}

revise(1).pipe(
  switchMap(reviseResult => forkJoin(of(reviseResult), getById(reviseResult.id))),  
).subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js"></script>

答案 1 :(得分:1)

出于记录,我相信Angular会基于this package.json使用与我们其他人相同的rxjs库。

幸运的是,rxjs提供了许多以不同方式完成任务的选项。我个人还没有以这种方式使用扩展,但是它看起来像是一个非常简洁的实现。

执行此操作的一种方法是创建一个新接口来容纳这两种类型:

export interface MyTypes {
  rev: ArticleRevision;
  article: Article;
}

通过这种方式,您可以使用switchMap operator从流中返回一种类型,并在一种类型上设置两个响应的值并返回可观察值。

草稿

export interface MyTypes {
  rev: ArticleRevision;
  article: Article;
}
private reviseArticle(article: article, revisionParams: ArticleRevisionParams): Observable<MyTypes> =>
  this.endpoint.articles.revise(article.id, revisionParams)
    .pipe(
      switchMap((rev: ArticleRevision) =>
        this.endpoint.articles.getById(article.id)
          .pipe(
            switchMap((art: Article) => ({
              rev: rev,
              article: art,
            })
          )
    );

您还可以使用switchMap以可观察的方式返回两个值的数组(类似于上面的内容,只需将它们返回到数组中即可)。