RXJS - 观察者

时间:2018-06-01 21:41:20

标签: exception-handling rxjs

我是rxjs的新手并且正在努力处理异常处理。

采用以下代码

let sub = new Subject();

let observer1:Observer<String> =  {
    next : v => {
        console.log("next1-" + v);
        if(v==='fail') {
            throw new Error("fail1");
        }
    },
    error : e => console.error("error1-" + e),
    complete : () => console.log("complete1")
};
sub.subscribe(observer1);

try {
    sub.next("msg1");
    sub.next("msg2");
    sub.next("fail");
    sub.next("msg3");
} catch(e) {
    console.log("Caught:" + e);
}

console.log("That's all");

据我所知,在异常之后,主题基本上已经死了,msg3永远不会成功。

我似乎无法弄清楚如何捕获Observer下一个方法中抛出的异常。

我得到的输出是

> next1-msg1 next1-msg2 next1-fail That's all
> /Users/peter/playground/rxjsstuff/node_modules/rxjs/internal/util/hostReportError.js:9
>     setTimeout(function () { throw err; });
>                              ^
> 
> Error: fail1
>     at Object.next (/Users/peter/playground/rxjsstuff/dist/rxjs1.js:97:19)
>     at SafeSubscriber.__tryOrUnsub (/Users/peter/playground/rxjsstuff/node_modules/rxjs/internal/Subscriber.js:263:16)
>     at SafeSubscriber.next (/Users/peter/playground/rxjsstuff/node_modules/rxjs/internal/Subscriber.js:201:22)
>     at Subscriber._next (/Users/peter/playground/rxjsstuff/node_modules/rxjs/internal/Subscriber.js:139:26)
>     at Subscriber.next (/Users/peter/playground/rxjsstuff/node_modules/rxjs/internal/Subscriber.js:103:18)
>     at Subject.next (/Users/peter/playground/rxjsstuff/node_modules/rxjs/internal/Subject.js:63:25)
>     at Object.<anonymous> (/Users/peter/playground/rxjsstuff/dist/rxjs1.js:107:9)
>     at Module._compile (internal/modules/cjs/loader.js:678:30)
>     at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
>     at Module.load (internal/modules/cjs/loader.js:589:32)

我认为我错过了一些基本的东西,但我似乎找不到什么。

我想高级问题是 - 当Subject调用next时,如何处理Observer的下一个方法中抛出的错误/异常?

欢迎所有提示!

的Tx

彼得

1 个答案:

答案 0 :(得分:0)

简短的回答是,你不能也不应该。一个可观察的来源如何知道观察者可以抛出哪种错误?

答案很长,RxJS中的错误处理在版本6中已经发生了变化 -

如果您查看Subjectnext的实施情况,您会发现没有错误处理:

next(value?: T) {
  if (this.closed) {
    throw new ObjectUnsubscribedError();
  }
  if (!this.isStopped) {
    const { observers } = this;
    const len = observers.length;
    const copy = observers.slice();
    for (let i = 0; i < len; i++) {
      copy[i].next(value);
    }
  }
}

主题只是循环观察者,每个人都next

但是,每个观察者都被包裹在Subscriber中。如果您查看subscribe的来源,您会看到通过将观察者传递给toSubscriber来创建Subscriber

特别是,创建的订阅者是SafeSubscriber。这就是错误处理的地方。

如果您查看SafeSubscriber中的next,您会看到__tryOrUnsub被调用:

next(value?: T): void {
  if (!this.isStopped && this._next) {
    const { _parentSubscriber } = this;
    if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
      this.__tryOrUnsub(this._next, value);
    } else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
      this.unsubscribe();
    }
  }
}

__tryOrUnsub将尝试调用观察者的next,如果发生错误,它将取消订阅观察者的来源。

__tryOrUnsub捕获的任何错误都将使用hostReportError报告 - 它会异步抛出错误,以便调用堆栈不会被解除。这样做是为了使一个观察者发生的错误不会影响其他观察者。

如果你向你的例子中添加第二个观察者 - 你没有抛出 - 你应该看到第二个观察者表现得像你期望的那样并且接收"msg3"

Ben Lesh在recent presentation中解释了这些变化及其产生的原因。你可能想看一下。