Skip to content

Error Handling

Vitaly Tomilov edited this page Nov 22, 2021 · 65 revisions

Due to the synchronous nature of iterables here, you can always resort to the regular try/catch at the point where iteration is triggered in your code. This however presents some problems:

  • Reusable iterables can trigger different errors, depending on usage + input data, which means manual error handling will be required at every point of triggering an iteration.
  • Verbose error-handling coding around every use of iterables is a fairly poor and time-consuming practice.

That's why here we are covering error handling strictly during/inside iteration, as values are retrieved one by one. This library supports explicit + implicit ways of handling iteration errors, as documented below.

Explicit error handling

You can handle all upstream iteration errors with a catchError operator at the end of the pipeline:

pipe(iterable, ...operators, catchError((error, ctx) => {
    // Handling the error (logging it, etc)

    // After that, you can do any of the following:
    //
    //  - nothing (we let it skip the value);
    //  - provide a new/alternative value (via ctx.emit(value));
    //  - re-throw the original error;
    //  - throw a new error.
}))

Parameters passed into the error handler:

  • error - the original error that was thrown;
  • ctx - iteration error context - see IErrorContext type.

When the handler wants to provide an alternative iteration value, it has to call ctx.emit(value).

Implicit error handling

You can use catch on any piped iterable:

pipe(iterable, ...operators)
    .catch((error, ctx) => {
    });

This will simply append catchError to the end of the pipeline, so the result is the same as with the explicit error handling. However, this adds the flexibility of handling errors separately from the pipeline implementation.

Chaining error handlers

You can chain as many error handlers as you want, each handling what's upstream, after the last error handler.

For explicit error handling, this means you can have any number of catchError operators inside the pipeline:

pipe(iterable, operator1, catchError, operator2, operator3, catchError);
//=> first catchError will handle errors thrown by operator1
//=> second catchError will handle errors thrown by operator2 and operator3
//=> second catchError will handle all errors, if the first catchError re-throws

For implicit error handling, this means you can chain any number of catch handlers at the end of the pipeline, each will be appending another catchError to the end of the pipeline:

pipe(iterable, ...operators)
    .catch() // first handler
    .catch() // second handler
    .catch() // third handler

// this will produce:
// pipe(iterable, ...operators, catchError, catchError, catchError);
Clone this wiki locally