RxJS - 发生错误时观察到的不会完成

Posted

技术标签:

【中文标题】RxJS - 发生错误时观察到的不会完成【英文标题】:RxJS - observable doesn't complete when an error occurs 【发布时间】:2016-02-20 10:04:00 【问题描述】:

当我从头开始创建一个可观察对象,并出现观察者错误,然后完成时,订阅的完成部分永远不会被调用。

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

发生错误时为什么不完成?

【问题讨论】:

【参考方案1】:

另一个可能也是最简单的解决方案可能是使用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")
);

【讨论】:

就像一个魅力,当 finally() 不起作用时出现错误【参考方案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 
              )

【讨论】:

【参考方案3】:

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

一个 Observable 可以发出零个或多个 OnNext 通知,每个通知代表一个发射的项目,然后它可以通过 OnCompleted 或 OnError 通知跟随这些发射通知,但不能两者兼而有之。在发出 OnCompleted 或 OnError 通知后,它可能不会再发出任何进一步的通知。`

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

【讨论】:

【参考方案4】:

当我有同样的问题时,我碰到了这个github issue。

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

从该线程中引用 Aleksandr-Leotech:

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

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

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

    使用网络套接字。您将收到多个成功回调,但在某个时间点,您与后端的通信将停止,您将获得 complete 和 finally,除非您有一些错误,这将调用 error 和 finally。

因此,您可能会收到多次或没有成功调用、零次或一次错误调用、零次或一次完成以及最终是零次或一次。

【讨论】:

以上是关于RxJS - 发生错误时观察到的不会完成的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS / rxjs:订阅时观察不到错误

Rxjs:将中间订阅和完整的可观察对象合并,并整体完成

退订 RxJS 可观察到的影响

带有 rxjs 错误的相关请求:可观察 _isScalar: false, _subscribe: f

如何在可观察的地图中抛出错误(rxjs 6,ng6)

Angular 不会导入显示错误的 Rxjs