1

I am playing around with Rxjs, observables and maps, and I found a strange behavior for Observable.throw(error) that I cannot explain.

If I have a Rx stream that uses a map operator, and I want to interrupt the process, I would have expected the method Observable.throw to be appropriate, however, this does not seem to be the case.

Consider the following example:

Rx.Observable.just("test 1").subscribe(
    x => console.log(x),
  err => console.log(err),
  () => console.log("done, no errors")
);

Now let's introduce an error, if I use the regular throw from Javascript it works as expected:

Rx.Observable.just("test 2").map(
    x => { throw new Error(x) }
).subscribe(
    x => console.log(x),
  err => console.log(err),
  () => console.log("done - error was thrown, as expected")
);

Output:

Error: test 2 at Rx.Observable.just.map.x ((index):58) at c (rx.all.compat.js:61) at e.onNext (rx.all.compat.js:5169) (...)

But if I use Rx.Observable.throw(...), the error callback from the following subscriber is never called, and the next callback will be called instead with some strange object that seems to be an Rx error object.

Rx.Observable.just("test 3").map(
    x => Rx.Observable.throw(x)
).subscribe(
    x => console.log(x),
  err => console.log(err),
  () => console.log("done - it does not work... why?")
);

Output:

b_subscribe: f(a)error: "test 3" scheduler: a__proto__: g

As @Whymarrh pointed out, it seems to work fine if I use a flatMap operator instead.

Documentation for map:

The Map operator applies a function of your choosing to each item emitted by the source Observable, and returns an Observable that emits the results of these function applications.

Documentation for Observable.throw:

Returns an observable sequence that terminates with an exception, using the specified scheduler to send out the single onError message.

Does anyone know why when using Observable.throw inside the map operator the error callback is not called, and why the process is not interrupted?

Example in jsfiddle

I know that I can just use the regular throw and move on, I already have a working solution, I am posting this question out of curiosity to have a better understanding of how the framework works.

Quick reminder: stackoverflow has a be nice policy.

yms
  • 10,361
  • 3
  • 38
  • 68
  • 1
    Using `flatMap` seems to work for me (and that would be the expected solution): https://jsbin.com/bododomeku/edit?js,console (I'm using JS Bin here to have console output handy.) – Whymarrh Feb 07 '17 at 23:08
  • I voted to close the issue as "caused by a problem that can no longer be reproduced or a simple typographical error. While similar questions may be on-topic here, **this one was resolved in a manner unlikely to help future readers**." (Emphasis is mine.) Sorry, I don't think there's much to this here, you didn't really read the output. Even if you were to reword the question to ask why returning an Observable doesn't work as expected with `map` there would be a bunch of duplicates that offer `flatMap` as the solution. – Whymarrh Feb 07 '17 at 23:38
  • To follow up to your edit, `flatMap` is the operator you need if you want to return an Observable (`Rx.Observable.throw(error)`) instead of a value (`throw new Error()`). Using `map` will result in `onNext` being called with a stream that has an error in it. – Whymarrh Feb 07 '17 at 23:41
  • 1
    Ah, sorry, then it's a duplicate of http://stackoverflow.com/q/33471526/1267663 (though I'd recommend http://stackoverflow.com/a/33258858/1267663 since it is a better answer) – Whymarrh Feb 07 '17 at 23:58
  • If you feel that it's not a duplicate, I think you'll need to edit the question significantly to make it so – Whymarrh Feb 07 '17 at 23:59
  • 2
    @yms `throw` throws an exception that simply bubbles to the top of the process. `Observable.throw` just creates a structure representing an error. To `map`, it's a value like any other, to call the success handler. To `flatMap`, it will have the structure and be unwrapped, to call the error handler. – Bergi Feb 08 '17 at 00:20
  • See also https://namitamalik.github.io/Map-vs-FlatMap/ – Bergi Feb 08 '17 at 00:30
  • 2
    Do you think I should reopen and post my comments as an answer? Btw, for a language-independent view check out [this](http://stackoverflow.com/a/8447872/1048572) – Bergi Feb 08 '17 at 18:33

1 Answers1

0

One of the comments properly answers this question:

throw new Error(x) throws an exception that simply bubbles to the top of the process.

x => Rx.Observable.throw(x) just creates a structure representing an error. To the map operator, this structure is a value like any other, to call the success handler. flatMap on the other hand will take the structure and unwrapped it, then call the error handler.

yms
  • 10,361
  • 3
  • 38
  • 68