How to handle promise rejection when creating a highland stream from a promise?

647 Views Asked by At

I am using [email protected] on [email protected] via typescript. Given this code snipplet:

import * as highland from "highland";
import * as lodash from "lodash/fp";

const range = lodash.range(0, 10);
const createPromise = async (i: number): Promise<number> => {
    if (i % 2 !== 0) {
        return Promise.resolve(i);
    }
    return Promise.resolve(null);
};

highland(range).map((i) => {
        return highland(createPromise(i));
    })
    .flatten() // resolving the promises
    .compact() // removing the null values
    .toArray((items) => console.log(items));

it will return my expected output of:

[ 1, 3, 5, 7, 9 ]

Yet in my codebase I have promises that don't return null values yet will reject the promise. In that case though, highland crashes:

const createPromise = async (i: number): Promise<number> => {
    if (i % 2 !== 0) {
        return Promise.resolve(i);
    }
    return Promise.reject("Some rejection message");
};


highland(range).map((i) => {
        return highland(createPromise(i));
    })
    .flatten()
    .toArray((items) => console.log(items));

will throw:

events.js:188
      throw err;
      ^

Error: Unhandled "error" event. (Invalid)
    at Stream.emit (events.js:186:19)
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1908:18
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1593:9
    at Stream.s._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1549:9)
    at Stream.write (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1647:18)
    at Stream._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:974:26)
    at push (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1515:19)
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:3918:13
    at Stream.s._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1549:9)
    at Stream.write (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1647:18)
    at Stream._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:974:26)
    at push (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1515:19)
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:2458:13
    at Stream.s._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1549:9)
    at Stream.write (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1647:18)
    at Stream._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:974:26)
    at Stream.write (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1647:18)
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:680:15
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:3606:17
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1593:9
    at Stream.s._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1549:9)
    at Stream.write (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1647:18)
    at Stream._send (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:974:26)
    at Stream.write (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:1647:18)
    at /home/philipp/rate-pipeline/node_modules/highland/lib/index.js:680:15
    at Immediate._onImmediate (/home/philipp/rate-pipeline/node_modules/highland/lib/index.js:541:17)
    at runCallback (timers.js:794:20)
    at tryOnImmediate (timers.js:752:5)
    at processImmediate [as _immediateCallback] (timers.js:729:5)

I know that I could transform my promises' rejection into null values and compact them as a workaround, yet I rather deal with the promise rejection itself.

How can I only work on successful promises streams and ignore the failing ones using highland? How am I supposed to handle the error event?

1

There are 1 best solutions below

1
On BEST ANSWER

Use the _.errors method:

Extracts errors from a Stream and applies them to an error handler function. Returns a new Stream with the errors removed (unless the error handler chooses to rethrow them using push). Errors can also be transformed and put back onto the Stream as values.

For your use case this is the least required implementation:

highland(range).map((i) => {
    return highland(createPromise(i));
  })
  .flatten()
  .errors(() => {})
  .toArray((items) => console.log(items));

and it will output:

[ 1, 3, 5, 7, 9 ]

It's possible to act on error and return custom values to the stream or to re-throw an error:

.errors((error, push) => {
   if(error.foo === "bar") {
     push(null, null); // pushes null to the result stream
   } else {
     push(err); // re-throws
   }
})