发生错误时,rxjs observable无法完成

时间:2015-11-18 15:26:09

标签: javascript reactive-programming rxjs

当我从头开始创建一个observable并且有观察者错误,然后完成时,永远不会调用订阅的完成部分。

var observer = Rx.Observable.create(function(observer){
    observer.onError(new Error('no!'));
    observer.onCompleted();
})

observer.subscribe(
    function(x) { console.log('succeeded with ' + x ) },
    function(x) { console.log('errored with ' + x ) },
    function() { console.log('completed') }
)

输出结果为:

errored with Error: no!

我希望它是:

errored with Error: no!
completed

如果我更改代码以调用onNext而不是onError,则observable正确完成:

var observer = Rx.Observable.create(function(observer){
    observer.onNext('Hi!');
    observer.onCompleted();
})

observer.subscribe(
    function(x) { console.log('succeeded with ' + x ) },
    function(x) { console.log('errored with ' + x ) },
    function() { console.log('completed') }
)

我得到了预期的输出:

succeeded with Hi! 
completed

发生错误时为什么没有完成?

4 个答案:

答案 0 :(得分:39)

这是因为错误意味着完成,因此与onCompleted相关联的回调永远不会被调用。您可以在此处查看可观察量的Rxjs合约(http://reactivex.io/documentation/contract.html):

  

Observable可以制作零个或多个OnNext通知,每个通知代表一个发出的项目,然后它可以通过OnCompleted或OnError通知跟踪这些发射通知,但不能同时通过两者。在发出OnCompleted或OnError通知后,它可能不会再发出任何通知。

对于错误管理,您可以查看: https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/errors.md

答案 1 :(得分:14)

当我遇到同样的问题时,我碰到了github issue

在这种情况下,显然需要使用finally Observable对象的方法。

从该线程引用Aleksandr-Leotech:

  

完成并最终是完全不同的事情。完成意味着   可观察到的蒸汽成功完成。因为你可以拥有   许多成功电话。最后意味着蒸汽已经结束   成功与否。

     

HTTP请求并不明显,但想象另外两个   场景。

     
      
  1. 鼠标事件。你将获得永无止境的成功   回调,但你永远不会收到或完成,因为   用户事件永远不会停止(除非您触发异常)   有缺陷的代码,然后你会得到错误,最后)。

  2.   
  3. 使用网络套接字。您将获得多次成功回调,但在某个时间点,您与后端的通信将停止,您将获得完整和最终,除非您有一些错误,这将最终调用错误。

  4.         

    所以,你可能会得到多次或没有成功的调用,零或一次错误调用,零或一个完整,零或一个最终。

答案 2 :(得分:5)

另一个可能也是最简单的解决方案可能是使用add()函数。
在这种情况下,无论发生错误,该语句将始终执行 或成功调用(与大多数编程语言中的finally类似)。

observer.subscribe(
    function(x) { console.log('succeeded with ' + x ) },
    function(x) { console.log('errored with ' + x ) },
    function() { console.log('completed') }
)
.add(() => {
    console.log("Will be executed on both success or error of the previous subscription")
);

答案 3 :(得分:2)

要在 observable 完成或出错时运行回调,您应该使用 finalize。

例如:

this.service.yourObservable
            .pipe(
               finalize(() => {
                 // * This will always run when observable finishes the stream
                 console.log("Finally!");
                 // * callback for finally
                })  
             ).subscribe(
              {
               next: () => { // * Callback for success },
               error: () => { // * Callback for error },
               complete: () => {// * This gets called only on success }
              })