user4676340
user4676340

Reputation:

RxJS : how to throw an error then catch it?

This is not related to a bug I am encountering, but rather a syntax issue.

The workflow is simple :

To manage that, my current code is this :

Boilerplate

private _getBoolean() { return this.http.get(...); }
private _getData() { return this.http.get(...); }

Current code

public getData() {
  return this._getBoolean().pipe(
    filter(bool => {
      if(!bool) {
        console.warn('Wrong server answer, stream stopped');
        return false;
      }
      return true;
    }),
    switchMap(bool => this._getData())
  );
}

And I don't know why, but it doesn't feel natural and optimized to me.

I thought that there would be something that simplifies the syntax, something like this

public getData() {
  return this._getBoolean().pipe(
    throwError(bool => bool ? new Error('Wrong server answer, stream stopped') : null),
    catchError(err => console.warn(err)),
    switchMap(bool => this._getData())
  );
}

Is there something along the lines of that, or do I have the correct syntax ?

Upvotes: 1

Views: 5064

Answers (3)

tlt
tlt

Reputation: 15191

instead of:

public getData() {
  return this._getBoolean().pipe(
    throwError(bool => bool ? new Error('Wrong server answer, stream stopped') : null),
    catchError(err => console.warn(err)),
    switchMap(bool => this._getData())
  );
}

why not something like:

public getData() {
  return this._getBoolean().pipe(
    tap(result => !result && throwError('Wrong server answer, stream stopped')),
    switchMap(bool => this._getData()),
    catchError(err => console.warn(err))
  );
}

Upvotes: 1

Sam Herrmann
Sam Herrmann

Reputation: 6966

Consider the following observable below that emits value 1 to 4. Let's say an error is thrown when the value is 3. That error can be caught in the catchError operator or it can be caught within the subscribe. I believe it depends on the specific use case whether you let the error bubble all the way up to the subscriber or whether it should be handled somewhere upstream of the subscriber.

of(1, 2, 3, 4).pipe(
  // Throw error when value is 3
  tap(value => { if(value === 3) throw new Error('Oops!') }),
  catchError(err => {
    console.log('Catch error in operator', err);

    // You can rethrow the same error or a new error
    // return throwError(err);

    // Or you can handle the error and return a new observable
    return of(3)
  })
).subscribe(
  value => console.log(value),
  // If `catchError` returns a new observable, then the error 
  // function here will not be called
  err => console.log('Catch error within subscribe', err),
  () => console.log('Done!')
)

Note that in this example, even if the error is being handled the observable completes and the value 4 is never emitted. If you wish to keep the observable alive when en error is encountered then have a look at this StackOverflow answer.

Upvotes: 1

Tomas
Tomas

Reputation: 3436

I'm not sure if I get your issue correctly, but you might replace

    console.warn('Wrong server answer, stream stopped');
    return false;

With

   Observable.throw('Some error cause')

And then catch it with nearest catch block in your stream, which gives you basically change to: - Stop stream if you re-throw error - Restart it if you return input observable - return completely new observable

public getData() {
  return this._getBoolean().pipe(
    filter(bool => {
      if(!bool) {
        console.warn('Wrong server answer, stream stopped');
        //return false;
        Observable.throw('I got false where I expected true')
      }
      return true;
    }),
    switchMap(bool => this._getData())
  );
}

And then:

getData()
.any()
.operator()
.you()
.wish()
.catch(e => {
  /* Here stream will be terminated on thrown error */
})

Upvotes: 0

Related Questions