在订阅中调用subscribe是一种好方法吗?

Yas*_*apu 18 angular2-observables angular angular6

this.service.service1().subscribe( res1 => {
  this.service.service1().subscribe( res2 => {
    this.service.service1().subscribe( res3 => {
      this.funcA(res1, res2, res3);
  });
  });
});
Run Code Online (Sandbox Code Playgroud)

我需要将三个数据从三个不同的API传递给一个函数.

在订阅中订阅是一种好习惯吗?

如果没有,请建议最佳方式.

Mar*_*hes 24

正确的方法是以某种方式组合各种可观察量,然后订阅整体流程 - 你如何构成它们将取决于你的确切要求.

如果你可以并行执行所有操作:

forkJoin(
   this.service.service1(), this.service.service2(), this.service.service3()
).subscribe((res) => {
   this.funcA(res[0], res[1], res[2]);
});
Run Code Online (Sandbox Code Playgroud)

如果每个都取决于前一个的结果:

this.service.service1().pipe(
    flatMap((res1) => this.service.service2(res1)),
    flatMap((res2) => this.service.service3(res2))
).subscribe((res3) => {
    // Do something with res3.
});
Run Code Online (Sandbox Code Playgroud)

... 等等.有许多不同的运算符来组成可观察量.

  • 它将按照编码顺序返回结果,但我不知道它是否会保证以指定的顺序启动它们.但是,由于它们是HTTP请求,即使它们以特定顺序启动,也不可能保证服务器接收和处理它们的顺序,除非您按顺序形成它 - 所以如果这很重要,则需要使用类似flatMap链,你在开始下一个@PankajParkar之前等待一个 (3认同)
  • 假设这些是 HTTP 请求,您将如何处理每种情况下的 HTTP 错误,尤其是在 flatMap 示例中?另外,如果我正确阅读以下内容,如果我们需要确保完整性的顺序,我们需要使用 `concatMap` 而不是 `flatMap`:https://www.learnrxjs.io/operators/transformation/concatmap。 html (2认同)
  • concatMap vs flatMap将取决于您的用例@AsGoodAsItGets-可以确保上面示例中的完成顺序。对于错误处理,在上面的flatMap示例中,如果(说)service2错误,则不会调用service3,它将转到传递给订阅的错误处理函数(如果传递了一个)。如果您想更早地捕获它们,可以在管道中使用catchError。 (2认同)
  • 如果您想单独处理来自每个服务的错误怎么办?即服务 1 失败的一个错误处理程序,服务 2 的另一个错误处理程序,依此类推?无论如何,我无法想象超过 2 个订阅的实际情况,但只是想知道它将如何构建。 (2认同)

Lia*_*iam 16

尽管上述所有内容都有助于为这个特定问题提供解决方案,但它们似乎都没有解决这里明显的根本问题,特别是:

在 subscribe 中调用 subscribe 是个好方法吗?

太长了;博士

不,在订阅中调用订阅是不好的。


为什么?

好吧,因为这不是函数式编程应该如何工作的。你不是在功能上思考,而是在程序上思考。这本身不一定是问题,但使用 rxjs (和其他反应式编程扩展)的全部目的是编写函数代码。

我不会详细介绍函数式编程是什么,但本质上函数式编程的要点是将数据视为流。由函数操作并由订阅者使用的流。一旦您在另一个订阅中添加订阅,您就可以在消费者(而不是流内)中操作数据。所以你的功能流现在被破坏了。这可以防止其他使用者在您的代码中进一步利用该流。因此,您已将功能流转变为过程。

在此输入图像描述

图像来源,上面以及有关纯函数式编程的更多信息在这里


Ant*_*e V 7

您可以使用 forkJoin将它们组合Observables成一个值Observable

forkJoin(
  this.service.service1(),
  this.service.service2(),
  this.service.service3()
).pipe(
  map(([res1, res2, res3 ]) => {
    this.funcA(res1, res2, res3);
  })
Run Code Online (Sandbox Code Playgroud)

  • 我不认为它是等价的,因为你在这里并行调用它,而作者按顺序调用它 (2认同)