Angular 6 / Rxjs-基础知识:可观察到的成功,错误,最后

时间:2018-06-28 13:17:26

标签: angular rxjs observable finally

我正在最新的Angular 6上构建体系结构,而来自AngularJS的事情让我无法安心:HTTP请求的基本处理。

因此,出于问题的原因,假设我想要一个可观察的对象。因为这似乎是Angular的未来。

我是从AngularJS的一个非常优雅的东西开始的:

   service.getAll()
    .then(onSuccess) // I process the data
    .catch(onError) // I do whatever needed to notify anyone about the issue
    .finally(onFinally); // I stop the loading spinner and other stuff

现在在Angular 6 / RxJS 6中,我不明白为什么一切都如此复杂并且看起来不正确。

我可以找到两种方法来完成上述工作:

  1. 完整管道

    this.service.getAll()
        .pipe(
            map((data) => this.onSuccess(data)),
            catchError(error => of(this.handleError(error))),
            finalize(() => this.stopLoading())
        )
        .subscribe();
    

由于我们必须使用pipe进行终结处理,因此我不妨对所有内容都使用pipe,我认为最好将所有内容按相同顺序进行。但是现在我们必须扔一些东西,叫做“ of”(不是很容易理解),我不喜欢这样。

  1. 半管 因此,我尝试了另一个想法,只用了我需要的管道(完成),并保留了订阅回调。

    this.service.getAll()
    .pipe(
        finalize(() => this.stopLoading())
    )
    .subscribe(
        (data) => this.onSuccess(data),
        (error) => this.handleError(error)
    );
    

但是,很好。是不是有点落后了?我们仍然有没有实际名称的回调,并且在读取处理和错误之前完成确定。很奇怪。

所以我绝对不了解某些内容。而且我在网上找不到与此基本问题相关的任何内容。您要么有人想要“成功并最终”,要么有人想要“成功与错误”,但是没人想要其中的三个。 也许我年纪太大了,我不了解关于它的最新最佳实践(如果是,请教育我!)。

我的需求很简单:
1.我要处理从服务获得的数据
2.我想获取错误以便显示给用户
3.我想停止在呼叫之前刚开始的​​加载微调器,或者在第一个呼叫成功或失败后再打另一个呼叫(我真的想要一个最终的呼叫)

如何使用可观察的方式处理基本的HTTP调用?

(请不要,我不需要任何.toPromise,我想了解如何处理新内容)

3 个答案:

答案 0 :(得分:19)

我认为有一个关键的误解:

  

您要么有人想要“成功并最终”,要么有人想要“成功与错误”,但没人想要其中的三个。

这并非完全正确。每个Observable可以发送零个或多个next通知和一个errorcomplete通知,但不能同时发送。例如,当成功进行HTTP调用时,您将收到一个next和一个complete通知。根据错误的HTTP请求,您将只有一个error通知,仅此而已。参见http://reactivex.io/documentation/contract.html

这意味着您永远不会发射errorcomplete的Observable。

然后是finalize运算符。处置链时(包括普通的取消订阅),将调用此运算符。换句话说,它在errorcomplete通知之后称为之后

因此,第二个示例是正确的。我了解您在订阅之前加入finalize看起来很奇怪,但是实际上来自Observable来源的每个发射都从上到下先到达订阅者,然后发出errorcomplete通知它触发处理程序处理程序从下至上(以相反顺序),并在此时调用finalize。参见https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subscriber.ts#L150-L152

在您的示例中,使用finalize与自己将处置处理程序添加到Subscription对象中相同。

const subscription = this.service.getAll()
  .subscribe(
    (data) => this.onSuccess(data),
    (error) => this.handleError(error)
  );

subscription.add(() => this.stopLoading());

答案 1 :(得分:4)

Observable的subscribe方法接受3个可选函数作为参数

  • 第一个处理由以下事件引发的数据的人 可观察的
  • 第二个处理发生的错误
  • 第三个在Observable完成后要做的事

因此,如果我理解正确,则可以使用如下所示的代码实现所需的目标

this.service.getAll()
.subscribe(
    data => this.onSuccess(data),
    error => this.handleError(error),
    () => this.onComplete()
);

请考虑使用http:// observables进行调用可以在遇到争用情况时重试(请参阅retry运算符)(通过使用switchMap运算符)。我认为这是Angular团队为http客户端选择这种方法的主要原因。

总的来说,我认为值得一开始了解Observables和一些最重要的运算符的工作方式(除了上述运算符之外,我首先考虑mergeMapfilter,{{1 }}-但是还有很多其他内容很重要),因为它们可以大大简化异步非阻塞环境中的许多任务,例如浏览器(例如Node)。

答案 2 :(得分:1)

我认为正确的方法是使用Observable函数:next,err,complete。
这是如何触发完整功能的示例。
假设我们有BehaviorSubject对象:

let arr = new BehaviorSubject<any>([1,2]);

现在让我们假设我们要订阅它,并且如果我们获得值“ finish”,我们就想完成。

let arrSubscription = arr.asObservable().subscribe(
  data => {
      console.log(data)
      if(data === 'finish') {
        arr.complete()
      }
  },
  err => {
      console.log(err)
  },
  () => {
      console.log("Complete function triggered.")
  }
);
arr.next([3,4])
arr.next('finish')
arr.next([5,6])

控制台日志为:

[1,2]
[3,4]
finish
Complete function triggered.

由于我们触发了complete函数,因此不会触发BehaviorSubject的最后一个.next,因为err和complete函数是订阅的终止符。
这只是一个示例,说明您如何触发完整功能,从这里您可以执行所需的任何操作。