Johannes Schacht
Johannes Schacht

Reputation: 1334

Exception in subscription terminates Observable in Angular but not in Node

I have this example code sequence that I either run in Angular or in a node app. Behavior is different, and I would like to know why.

        of(1, 2, 3, 4).subscribe((x) => {
            console.log(`x: ${x}`);
            if (x === 2) {
                throw new Error('xxx');
            }
        });

When executing in node all four numbers are written to the console. Exception is shown afterwards.

When executing in Angular, e.g. in any ngOnInit(), it only logs 1 and 2 and then the Observable is terminated. The consequence is that any exception in a subscription block breaks the program.

Is there any description of why and how this difference in behavior.

Addendum: Reading more on the subject, the Angular (or more general the browser) behavior is what is to be expected. It is really the node.js behavior that is surprising. Why does the node.js program not stop after two digits?

Upvotes: 0

Views: 392

Answers (1)

MBB
MBB

Reputation: 1685

From the comments section, you are actually trying to figure out the difference in behavior between the rxjs v6 and v7 in terms of handling the consumer thrown unhandled errors.

In general throwing errors from the observers is a bad idea as it will lead to blocking of the observables if shared between multiple observers. This problem is handled in the v6 by improving the error handling mechanism as mentioned here SafeSubscriber and more specifically in next. Below snapshot of the next

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();
      }
    }
  }

If you see from the above snapshot when an unhandled error is thrown from the observer the code is trying to subscribe and then if error it is unsubscribing the observable in __tryOrUnsub. Finally the error is added to call stack and thrown once the call stack is empty from method hostReportError(once all the observers complete asynchronously). Below is the sample stackblitz to demonstrate the same.

https://stackblitz.com/edit/angular-ivy-v7dojh?file=src%2Fapp%2Fhello.component.ts

This logic further changed in v7 as mentioned by the this commit. The unsubscribing logic is removed and the asynchronous error call stack is maintained as shown below sample stackblitz, due to which the all the 4 elements are printed and the error is printed to console once the call stack is empty asynchronously usning reportUnhandledError -

https://stackblitz.com/edit/angular-ivy-p8zj2k?file=src%2Fapp%2Fhello.component.ts

Upvotes: 2

Related Questions